packages feed

morley 0.3.0.1 → 0.4.0

raw patch · 189 files changed

+18836/−3945 lines, 189 filesdep +bimapdep +first-class-familiesdep +gitrevdep −generic-arbitrarydep −qm-interpolated-stringdep ~constraintsdep ~megaparsecPVP ok

version bump matches the API change (PVP)

Dependencies added: bimap, first-class-families, gitrev, interpolate, pretty-terminal, show-type, spoon, tasty-hunit, unordered-containers

Dependencies removed: generic-arbitrary, qm-interpolated-string

Dependency ranges changed: constraints, megaparsec

API changes (from Hackage documentation)

- Lorentz.Arith: instance Lorentz.Arith.ArithOpHs Michelson.Typed.Arith.Compare Data.ByteString.Internal.ByteString Data.ByteString.Internal.ByteString
- Lorentz.Arith: instance Lorentz.Arith.ArithOpHs Michelson.Typed.Arith.Compare GHC.Integer.Type.Integer GHC.Integer.Type.Integer
- Lorentz.Arith: instance Lorentz.Arith.ArithOpHs Michelson.Typed.Arith.Compare GHC.Natural.Natural GHC.Natural.Natural
- Lorentz.Arith: instance Lorentz.Arith.ArithOpHs Michelson.Typed.Arith.Compare GHC.Types.Bool GHC.Types.Bool
- Lorentz.Arith: instance Lorentz.Arith.ArithOpHs Michelson.Typed.Arith.Compare Michelson.Text.MText Michelson.Text.MText
- Lorentz.Arith: instance Lorentz.Arith.ArithOpHs Michelson.Typed.Arith.Compare Tezos.Address.Address Tezos.Address.Address
- Lorentz.Arith: instance Lorentz.Arith.ArithOpHs Michelson.Typed.Arith.Compare Tezos.Core.Mutez Tezos.Core.Mutez
- Lorentz.Arith: instance Lorentz.Arith.ArithOpHs Michelson.Typed.Arith.Compare Tezos.Core.Timestamp Tezos.Core.Timestamp
- Lorentz.Arith: instance Lorentz.Arith.ArithOpHs Michelson.Typed.Arith.Compare Tezos.Crypto.KeyHash Tezos.Crypto.KeyHash
- Lorentz.Base: I :: Instr (ToTs inp) (ToTs out) -> (:->)
- Lorentz.Base: [unI] :: (:->) -> Instr (ToTs inp) (ToTs out)
- Lorentz.Base: compileLorentz :: (inp :-> out) -> Instr (ToTs inp) (ToTs out)
- Lorentz.Base: compileLorentzContract :: forall cp st. (NoOperation cp, NoOperation st, NoBigMap cp, CanHaveBigMap st) => Contract cp st -> Instr '[ToT (cp, st)] '[ToT ([Operation], st)]
- Lorentz.Base: instance Michelson.Typed.Haskell.Value.IsoValue (Lorentz.Base.Lambda inp out)
- Lorentz.Base: printLorentzContract :: forall cp st. (SingI (ToT cp), SingI (ToT st), NoOperation cp, NoOperation st, NoBigMap cp, CanHaveBigMap st) => Contract cp st -> LText
- Lorentz.Constraints: type CanHaveBigMap a = AllowBigMap (ToT a)
- Lorentz.Constraints: type KnownCValue a = (IsoValue a, Typeable (ToCT a), SingI (ToCT a))
- Lorentz.Constraints: type KnownValue a = (Typeable (ToT a), SingI (ToT a))
- Lorentz.Constraints: type NoBigMap a = ForbidBigMap (ToT a)
- Lorentz.Constraints: type NoOperation a = ForbidOp (ToT a)
- Lorentz.Discover: ExportedContractDecl :: Text -> Text -> ExportedContractDecl
- Lorentz.Discover: ExportedContractInfo :: Text -> ExportedContractDecl -> ExportedContractInfo
- Lorentz.Discover: [ecdName] :: ExportedContractDecl -> Text
- Lorentz.Discover: [ecdVar] :: ExportedContractDecl -> Text
- Lorentz.Discover: [eciContractDecl] :: ExportedContractInfo -> ExportedContractDecl
- Lorentz.Discover: [eciModuleName] :: ExportedContractInfo -> Text
- Lorentz.Discover: class IsContract c
- Lorentz.Discover: data ExportedContractDecl
- Lorentz.Discover: data ExportedContractInfo
- Lorentz.Discover: haskellExportsParser :: Parsec Void Text [ExportedContractInfo]
- Lorentz.Discover: instance (Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.ToT cp), Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.ToT st), Lorentz.Constraints.NoOperation cp, Lorentz.Constraints.NoOperation st, Lorentz.Constraints.NoBigMap cp, Lorentz.Constraints.CanHaveBigMap st) => Lorentz.Discover.IsContract (Lorentz.Base.Contract cp st)
- Lorentz.Discover: instance (Data.Singletons.Internal.SingI cp, Data.Singletons.Internal.SingI st) => Lorentz.Discover.IsContract (Michelson.Typed.Instr.Contract cp st)
- Lorentz.Discover: instance GHC.Classes.Eq Lorentz.Discover.ExportedContractDecl
- Lorentz.Discover: instance GHC.Classes.Eq Lorentz.Discover.ExportedContractInfo
- Lorentz.Discover: instance GHC.Show.Show Lorentz.Discover.ExportedContractDecl
- Lorentz.Discover: instance GHC.Show.Show Lorentz.Discover.ExportedContractInfo
- Lorentz.Discover: instance Lorentz.Discover.IsContract Michelson.Untyped.Aliases.Contract
- Lorentz.Discover: isHaskellModule :: FilePath -> Bool
- Lorentz.Discover: toUntypedContract :: IsContract c => c -> Contract
- Lorentz.Errors: instance (TypeError ...) => Data.String.IsString Lorentz.Errors.ErrorTag
- Lorentz.Errors: instance GHC.Classes.Eq Lorentz.Errors.ErrorTag
- Lorentz.Errors: instance GHC.Classes.Ord Lorentz.Errors.ErrorTag
- Lorentz.Errors: instance GHC.Show.Show Lorentz.Errors.ErrorTag
- Lorentz.Errors: instance Michelson.Typed.Haskell.Value.IsoValue Lorentz.Errors.ErrorTag
- Lorentz.Errors: type IsError err = (IsoValue err, KnownValue err, NoOperation err, NoBigMap err)
- Lorentz.Errors: type LorentzUserError e = (ErrorTag, e)
- Lorentz.Errors: unLorentzUserError :: LorentzUserError e -> e
- Lorentz.Errors: userFailWith :: forall err name s s'. (Typeable (ToT err), SingI (ToT err)) => UserFailInstr err name s s'
- Lorentz.Instr: createAccount :: (KeyHash & (Maybe KeyHash & (Bool & (Mutez & s)))) :-> (Operation & (Address & s))
- Lorentz.Instr: failTagged :: KnownValue a => MText -> (a & s) :-> t
- Lorentz.Instr: failText :: MText -> s :-> t
- Lorentz.Instr: failUnexpected :: HasCallStack => MText -> s :-> t
- Lorentz.Instr: failUsing :: (IsoValue a, KnownValue a, NoOperation a, NoBigMap a) => a -> s :-> t
- Lorentz.Macro: dipX :: forall (n :: Nat) inp out s s'. (DipX (ToPeano n) (Above (ToPeano n) inp) s s', (Above (ToPeano n) inp ++ s) ~ inp, (Above (ToPeano n) inp ++ s') ~ out) => (s :-> s') -> inp :-> out
- Lorentz.Macro: elevateX :: forall (n :: Nat) inp out s a. (DuupX (ToPeano (1 + n)) inp a, DipX (ToPeano (n + 1)) (Above (ToPeano (n + 1)) (a : inp)) (a : s) s, (a : (Above (ToPeano n) inp ++ s)) ~ out, a ~ At (ToPeano n) inp, (Above (ToPeano (n + 1)) (a : inp) ++ (a : s)) ~ (a : inp), (Above (ToPeano (n + 1)) (a : inp) ++ s) ~ (a : (Above (ToPeano n) inp ++ s)), ((1 + n) - 1) ~ n) => inp :-> out
- Lorentz.Macro: instance Lorentz.Macro.DipX 'Data.Vinyl.TypeLevel.Z '[] s s'
- Lorentz.Macro: instance Lorentz.Macro.DipX n h s s' => Lorentz.Macro.DipX ('Data.Vinyl.TypeLevel.S n) (a : h) s s'
- Lorentz.Macro: instance Lorentz.Macro.DuupX ('Data.Vinyl.TypeLevel.S 'Data.Vinyl.TypeLevel.Z) (a Lorentz.Base.& xs) a
- Lorentz.Macro: instance Lorentz.Macro.DuupX ('Data.Vinyl.TypeLevel.S n) xs a => Lorentz.Macro.DuupX ('Data.Vinyl.TypeLevel.S ('Data.Vinyl.TypeLevel.S n)) (x Lorentz.Base.& xs) a
- Lorentz.Macro: instance Michelson.Typed.Haskell.Value.IsoValue r => Michelson.Typed.Haskell.Value.IsoValue (Lorentz.Macro.VoidResult r)
- Lorentz.Test: CustomError :: Text -> ValidationError
- Lorentz.Test: lExpectUserError :: forall e. (Typeable (ToT e), IsoValue e) => (e -> Bool) -> InterpreterError -> Bool
- Lorentz.Test.Integrational: CustomError :: Text -> ValidationError
- Lorentz.Test.Integrational: lExpectUserError :: forall e. (Typeable (ToT e), IsoValue e) => (e -> Bool) -> InterpreterError -> Bool
- Lorentz.Value: ContractAddr :: Address -> ContractAddr
- Lorentz.Value: [unContractAddress] :: ContractAddr -> Address
- Lorentz.Value: newtype ContractAddr (cp :: Type)
- Michelson.EqParam: eqParam1 :: forall a1 a2 t. (Typeable a1, Typeable a2, Eq (t a1)) => t a1 -> t a2 -> Bool
- Michelson.EqParam: eqParam2 :: forall a1 a2 b1 b2 t. (Typeable a1, Typeable a2, Typeable b1, Typeable b2, Eq (t a1 b2)) => t a1 b1 -> t a2 b2 -> Bool
- Michelson.EqParam: eqParam3 :: forall a1 a2 b1 b2 c1 c2 t. (Typeable a1, Typeable a2, Typeable b1, Typeable b2, Typeable c1, Typeable c2, Eq (t a1 b1 c1)) => t a1 b1 c1 -> t a2 b2 c2 -> Bool
- Michelson.Interpret: [InterpretUntypedResult] :: (Typeable st, SingI st, HasNoOp st) => {iurOps :: [Operation], iurNewStorage :: Value st, iurNewState :: InterpreterState} -> InterpretUntypedResult
- Michelson.Interpret: data InterpretUntypedError
- Michelson.Interpret: data InterpretUntypedResult
- Michelson.Interpret: instance Formatting.Buildable.Buildable Michelson.Interpret.InterpretUntypedError
- Michelson.Interpret: instance GHC.Generics.Generic Michelson.Interpret.InterpretUntypedError
- Michelson.Interpret: instance GHC.Show.Show Michelson.Interpret.InterpretUntypedError
- Michelson.Interpret: instance GHC.Show.Show Michelson.Interpret.InterpretUntypedResult
- Michelson.Interpret.Unpack: UnpackEnv :: TcOriginatedContracts -> UnpackEnv
- Michelson.Interpret.Unpack: [ueContracts] :: UnpackEnv -> TcOriginatedContracts
- Michelson.Interpret.Unpack: data UnpackEnv
- Michelson.Macro: type ParsedUTestAssert = TestAssert ParsedOp
- Michelson.Parser: ProhibitedLetType :: Text -> CustomParserException
- Michelson.Parser: explicitType :: Parser Type
- Michelson.Parser.Error: ProhibitedLetType :: Text -> CustomParserException
- Michelson.Parser.Type: explicitType :: Parser Type
- Michelson.Runtime.GState: instance GHC.Classes.Eq Michelson.Runtime.GState.AddressState
- Michelson.Runtime.GState: instance GHC.Classes.Eq Michelson.Runtime.GState.ContractState
- Michelson.Runtime.GState: instance GHC.Classes.Eq Michelson.Runtime.GState.GStateUpdate
- Michelson.Runtime.GState: instance GHC.Generics.Generic Michelson.Runtime.GState.ContractState
- Michelson.Test.Integrational: CustomError :: Text -> ValidationError
- Michelson.TypeCheck.Error: ExtractionTypeMismatch :: TypeConvergeError -> TCTypeError
- Michelson.TypeCheck.Error: UnknownType :: T -> TCTypeError
- Michelson.TypeCheck.Helpers: onTypeCheckInstrTypeErr :: (MonadReader InstrCallStack m, MonadError TCError m, Typeable ts) => ExpandedInstr -> HST ts -> Text -> Either TypeConvergeError a -> m a
- Michelson.TypeCheck.TypeCheck: runTypeCheckTest :: TypeCheck a -> Either TCError a
- Michelson.TypeCheck.Types: data SomeValue
- Michelson.Typed.Annotation: N :: Notes' t -> Notes t
- Michelson.Typed.Annotation: NStar :: Notes t
- Michelson.Typed.Annotation: data Notes' t
- Michelson.Typed.Annotation: instance GHC.Classes.Eq (Michelson.Typed.Annotation.Notes' t)
- Michelson.Typed.Annotation: instance GHC.Show.Show (Michelson.Typed.Annotation.Notes p)
- Michelson.Typed.Annotation: instance GHC.Show.Show (Michelson.Typed.Annotation.Notes' t)
- Michelson.Typed.Annotation: mkNotes :: Notes' t -> Notes t
- Michelson.Typed.Annotation: notesCase :: r -> (Notes' t -> r) -> Notes t -> r
- Michelson.Typed.Arith: instance Michelson.Typed.Arith.ArithOp Michelson.Typed.Arith.Compare 'Michelson.Untyped.Type.CAddress 'Michelson.Untyped.Type.CAddress
- Michelson.Typed.Arith: instance Michelson.Typed.Arith.ArithOp Michelson.Typed.Arith.Compare 'Michelson.Untyped.Type.CBool 'Michelson.Untyped.Type.CBool
- Michelson.Typed.Arith: instance Michelson.Typed.Arith.ArithOp Michelson.Typed.Arith.Compare 'Michelson.Untyped.Type.CBytes 'Michelson.Untyped.Type.CBytes
- Michelson.Typed.Arith: instance Michelson.Typed.Arith.ArithOp Michelson.Typed.Arith.Compare 'Michelson.Untyped.Type.CInt 'Michelson.Untyped.Type.CInt
- Michelson.Typed.Arith: instance Michelson.Typed.Arith.ArithOp Michelson.Typed.Arith.Compare 'Michelson.Untyped.Type.CKeyHash 'Michelson.Untyped.Type.CKeyHash
- Michelson.Typed.Arith: instance Michelson.Typed.Arith.ArithOp Michelson.Typed.Arith.Compare 'Michelson.Untyped.Type.CMutez 'Michelson.Untyped.Type.CMutez
- Michelson.Typed.Arith: instance Michelson.Typed.Arith.ArithOp Michelson.Typed.Arith.Compare 'Michelson.Untyped.Type.CNat 'Michelson.Untyped.Type.CNat
- Michelson.Typed.Arith: instance Michelson.Typed.Arith.ArithOp Michelson.Typed.Arith.Compare 'Michelson.Untyped.Type.CString 'Michelson.Untyped.Type.CString
- Michelson.Typed.Arith: instance Michelson.Typed.Arith.ArithOp Michelson.Typed.Arith.Compare 'Michelson.Untyped.Type.CTimestamp 'Michelson.Untyped.Type.CTimestamp
- Michelson.Typed.Convert: instance Data.Typeable.Internal.Typeable s => GHC.Classes.Eq (Michelson.Typed.Instr.ExtInstr s)
- Michelson.Typed.Extract: TParameterConvergeError :: TypeConvergeError
- Michelson.Typed.Extract: TStorageConvergeError :: TypeConvergeError
- Michelson.Typed.Extract: TypeConvergeError :: T -> T -> TypeConvergeError
- Michelson.Typed.Extract: data TypeConvergeError
- Michelson.Typed.Extract: extractNotes :: Type -> Sing t -> Either TypeConvergeError (Notes t)
- Michelson.Typed.Extract: instance Formatting.Buildable.Buildable Michelson.Typed.Extract.TypeConvergeError
- Michelson.Typed.Extract: instance GHC.Classes.Eq Michelson.Typed.Extract.TypeConvergeError
- Michelson.Typed.Extract: instance GHC.Show.Show Michelson.Typed.Extract.TypeConvergeError
- Michelson.Typed.Haskell: ContractAddr :: Address -> ContractAddr
- Michelson.Typed.Haskell: [unContractAddress] :: ContractAddr -> Address
- Michelson.Typed.Haskell: newtype ContractAddr (cp :: Type)
- Michelson.Typed.Haskell.Instr.Helpers: class RSplit (l :: [k]) (r :: [k])
- Michelson.Typed.Haskell.Instr.Helpers: instance forall k (ls :: [k]) (r :: [k]) (l :: k). Michelson.Typed.Haskell.Instr.Helpers.RSplit ls r => Michelson.Typed.Haskell.Instr.Helpers.RSplit (l : ls) r
- Michelson.Typed.Haskell.Instr.Helpers: instance forall k (r :: [k]). Michelson.Typed.Haskell.Instr.Helpers.RSplit '[] r
- Michelson.Typed.Haskell.Instr.Helpers: rsplit :: forall f. RSplit l r => Rec f (l ++ r) -> (Rec f l, Rec f r)
- Michelson.Typed.Haskell.Instr.Product: instance (Michelson.Typed.Haskell.Instr.Product.GInstrConstruct x, Michelson.Typed.Haskell.Instr.Product.GInstrConstruct y, Michelson.Typed.Haskell.Instr.Helpers.RSplit (Michelson.Typed.Haskell.Instr.Product.GFieldTypes x) (Michelson.Typed.Haskell.Instr.Product.GFieldTypes y)) => Michelson.Typed.Haskell.Instr.Product.GInstrConstruct (x GHC.Generics.:*: y)
- Michelson.Typed.Haskell.Instr.Sum: instance (Michelson.Typed.Haskell.Instr.Sum.GInstrCase x, Michelson.Typed.Haskell.Instr.Sum.GInstrCase y, Michelson.Typed.Haskell.Instr.Helpers.RSplit (Michelson.Typed.Haskell.Instr.Sum.GCaseClauses x) (Michelson.Typed.Haskell.Instr.Sum.GCaseClauses y)) => Michelson.Typed.Haskell.Instr.Sum.GInstrCase (x GHC.Generics.:+: y)
- Michelson.Typed.Haskell.Value: ContractAddr :: Address -> ContractAddr
- Michelson.Typed.Haskell.Value: [unContractAddress] :: ContractAddr -> Address
- Michelson.Typed.Haskell.Value: instance Michelson.Typed.Haskell.Value.IsoValue (Michelson.Typed.Haskell.Value.ContractAddr cp)
- Michelson.Typed.Haskell.Value: newtype ContractAddr (cp :: Type)
- Michelson.Typed.Instr: [CAR] :: Instr ( 'TPair a b : s) (a : s)
- Michelson.Typed.Instr: [CDR] :: Instr ( 'TPair a b : s) (b : s)
- Michelson.Typed.Instr: [CREATE_ACCOUNT] :: Instr ( 'Tc 'CKeyHash : ( 'TOption ( 'Tc 'CKeyHash) : ( 'Tc 'CBool : ( 'Tc 'CMutez : s)))) ( 'TOperation : ( 'Tc 'CAddress : s))
- Michelson.Typed.Print: buildStack :: [T] -> Builder
- Michelson.Typed.Print: instance Formatting.Buildable.Buildable Michelson.Typed.T.T
- Michelson.Typed.Scope: bigMapConstrained :: Sing (t :: T) -> Maybe (Dict $ BigMapConstraint t)
- Michelson.Typed.Scope: checkBigMapConstraint :: forall t a. (SingI t, AllowBigMap t) => (BigMapConstraint t => a) -> a
- Michelson.Typed.Scope: type AllowBigMap t = FailOnBigMapFound (BadBigMapPair t)
- Michelson.Typed.Scope: type BigMapConstraint t = BadBigMapPair t ~ 'False
- Michelson.Typed.Value: CreateAccount :: !KeyHash -> !Maybe KeyHash -> !Bool -> !Mutez -> CreateAccount
- Michelson.Typed.Value: [OpCreateAccount] :: CreateAccount -> Operation' instr
- Michelson.Typed.Value: [caBalance] :: CreateAccount -> !Mutez
- Michelson.Typed.Value: [caDelegate] :: CreateAccount -> !Maybe KeyHash
- Michelson.Typed.Value: [caManager] :: CreateAccount -> !KeyHash
- Michelson.Typed.Value: [caSpendable] :: CreateAccount -> !Bool
- Michelson.Typed.Value: [ccDelegatable] :: CreateContract instr cp st -> !Bool
- Michelson.Typed.Value: [ccManager] :: CreateContract instr cp st -> !KeyHash
- Michelson.Typed.Value: [ccSpendable] :: CreateContract instr cp st -> !Bool
- Michelson.Typed.Value: [ttContractParameter] :: TransferTokens instr p -> !Value' instr p
- Michelson.Typed.Value: data CreateAccount
- Michelson.Typed.Value: instance Formatting.Buildable.Buildable Michelson.Typed.Value.CreateAccount
- Michelson.Typed.Value: instance GHC.Classes.Eq Michelson.Typed.Value.CreateAccount
- Michelson.Typed.Value: instance GHC.Show.Show Michelson.Typed.Value.CreateAccount
- Michelson.Untyped.Annotation: class RenderAnn t
- Michelson.Untyped.Annotation: instance Formatting.Buildable.Buildable Michelson.Untyped.Annotation.FieldAnn
- Michelson.Untyped.Annotation: instance Formatting.Buildable.Buildable Michelson.Untyped.Annotation.TypeAnn
- Michelson.Untyped.Annotation: instance Formatting.Buildable.Buildable Michelson.Untyped.Annotation.VarAnn
- Michelson.Untyped.Annotation: instance GHC.Show.Show (Michelson.Untyped.Annotation.Annotation Michelson.Untyped.Annotation.FieldTag)
- Michelson.Untyped.Annotation: instance GHC.Show.Show (Michelson.Untyped.Annotation.Annotation Michelson.Untyped.Annotation.TypeTag)
- Michelson.Untyped.Annotation: instance GHC.Show.Show (Michelson.Untyped.Annotation.Annotation Michelson.Untyped.Annotation.VarTag)
- Michelson.Untyped.Annotation: instance Michelson.Printer.Util.RenderDoc Michelson.Untyped.Annotation.FieldAnn
- Michelson.Untyped.Annotation: instance Michelson.Printer.Util.RenderDoc Michelson.Untyped.Annotation.TypeAnn
- Michelson.Untyped.Annotation: instance Michelson.Printer.Util.RenderDoc Michelson.Untyped.Annotation.VarAnn
- Michelson.Untyped.Annotation: instance Michelson.Untyped.Annotation.RenderAnn Michelson.Untyped.Annotation.FieldAnn
- Michelson.Untyped.Annotation: instance Michelson.Untyped.Annotation.RenderAnn Michelson.Untyped.Annotation.TypeAnn
- Michelson.Untyped.Annotation: instance Michelson.Untyped.Annotation.RenderAnn Michelson.Untyped.Annotation.VarAnn
- Michelson.Untyped.Instr: CREATE_ACCOUNT :: VarAnn -> VarAnn -> InstrAbstract op
- Michelson.Untyped.Instr: Op :: Instr -> Op
- Michelson.Untyped.Instr: [ooDelegatable] :: OriginationOperation -> !Bool
- Michelson.Untyped.Instr: [ooManager] :: OriginationOperation -> !KeyHash
- Michelson.Untyped.Instr: [ooSpendable] :: OriginationOperation -> !Bool
- Michelson.Untyped.Instr: [unOp] :: Op -> Instr
- Michelson.Untyped.Instr: instance Data.Aeson.Types.FromJSON.FromJSON Michelson.Untyped.Instr.Op
- Michelson.Untyped.Instr: instance Data.Aeson.Types.ToJSON.ToJSON Michelson.Untyped.Instr.Op
- Michelson.Untyped.Instr: instance Formatting.Buildable.Buildable Michelson.Untyped.Instr.Op
- Michelson.Untyped.Instr: instance GHC.Classes.Eq Michelson.Untyped.Instr.Op
- Michelson.Untyped.Instr: instance GHC.Generics.Generic Michelson.Untyped.Instr.Op
- Michelson.Untyped.Instr: instance GHC.Show.Show Michelson.Untyped.Instr.Op
- Michelson.Untyped.Instr: instance Michelson.Printer.Util.RenderDoc Michelson.Untyped.Instr.Op
- Michelson.Untyped.Instr: newtype Op
- Michelson.Untyped.Instr: type ExpandedInstrExtU = ExtInstrAbstract ExpandedOp
- Michelson.Untyped.Instr: type Instr = InstrAbstract Op
- Michelson.Untyped.Instr: type InstrExtU = ExtInstrAbstract Op
- Michelson.Untyped.Type: TypeParameter :: Type
- Michelson.Untyped.Type: TypeStorage :: Type
- Tezos.Crypto: PublicKey :: PublicKey -> PublicKey
- Tezos.Crypto: Signature :: Signature -> Signature
- Tezos.Crypto: [unKeyHash] :: KeyHash -> ByteString
- Tezos.Crypto: [unPublicKey] :: PublicKey -> PublicKey
- Tezos.Crypto: [unSignature] :: Signature -> Signature
- Tezos.Crypto: formatSecretKey :: SecretKey -> Text
- Tezos.Crypto: instance Formatting.Buildable.Buildable Tezos.Crypto.CryptoParseError
- Tezos.Crypto: instance Formatting.Buildable.Buildable Tezos.Crypto.SecretKey
- Tezos.Crypto: instance GHC.Classes.Eq Tezos.Crypto.CryptoParseError
- Tezos.Crypto: instance GHC.Show.Show Tezos.Crypto.B58CheckWithPrefixError
- Tezos.Crypto: instance GHC.Show.Show Tezos.Crypto.CryptoParseError
- Tezos.Crypto: mkPublicKey :: ByteArrayAccess ba => ba -> Either Text PublicKey
- Tezos.Crypto: newtype KeyHash
- Tezos.Crypto: newtype PublicKey
- Tezos.Crypto: newtype Signature
- Tezos.Crypto: parseSecretKey :: Text -> Either CryptoParseError SecretKey
- Tezos.Crypto: sign :: SecretKey -> ByteString -> Signature
- Util.Named: instance GHC.Classes.Eq a => GHC.Classes.Eq (Named.Internal.NamedF Data.Functor.Identity.Identity a name)
- Util.Peano: instance Data.Singletons.Internal.SingI n => Data.Singletons.Internal.SingI ('Data.Vinyl.TypeLevel.S n)
- Util.Peano: requiredLongerThan :: forall l a r. RequireLongerThan l a => (LongerThan l a => r) -> r
+ Lorentz: (#) :: (a :-> b) -> (b :-> c) -> a :-> c
+ Lorentz: ($) :: () => (a -> b) -> a -> b
+ Lorentz: (.) :: () => (b -> c) -> (a -> b) -> a -> c
+ Lorentz: (/->) :: CaseArrow name body clause => Label name -> body -> clause
+ Lorentz: (<>) :: Semigroup a => a -> a -> a
+ Lorentz: (>>) :: (a :-> b) -> (b :-> c) -> a :-> c
+ Lorentz: --
+ Lorentz: -- Documentation structure is not necessarily flat. If some doc item
+ Lorentz: -- Inline right here (default behaviour); 2. Put into definitions
+ Lorentz: -- Note that we require all doc items with "in definitions" placement to
+ Lorentz: -- and field value type. Used for error messages.
+ Lorentz: -- consolidates a whole documentation block within it, this block will
+ Lorentz: -- doc.
+ Lorentz: -- have <a>Eq</a> and <a>Ord</a> instances which comply the following
+ Lorentz: -- law: if two documentation items describe the same entity or property,
+ Lorentz: -- section.
+ Lorentz: -- they should be considered equal.
+ Lorentz: -- type (which has kind <tt>CT</tt>).
+ Lorentz: -- type.
+ Lorentz: -- value, the higher the section with this element will be placed.
+ Lorentz: -- | Display type-level information about UStore field with given marker
+ Lorentz: ArgumentUnpackFailed :: EntryPointLookupError
+ Lorentz: BigMap :: Map k v -> BigMap k v
+ Lorentz: ContractDoc :: DocBlock -> DocBlock -> Set SomeDocDefinitionItem -> Set DocItemId -> ContractDoc
+ Lorentz: ContractRef :: Address -> SomeEntryPointCall arg -> ContractRef
+ Lorentz: CustomError :: Label tag -> ErrorArg tag -> CustomError
+ Lorentz: DComment :: Text -> DComment
+ Lorentz: DDescription :: Markdown -> DDescription
+ Lorentz: DEntryPoint :: Text -> SubDoc -> DEntryPoint
+ Lorentz: DEntryPointArg :: Maybe DType -> [ParamBuildingStep] -> DEntryPointArg
+ Lorentz: DGitRevision :: GitRepoSettings -> Text -> Text -> DGitRevision
+ Lorentz: DVersion :: Natural -> DVersion
+ Lorentz: DocItemId :: Text -> DocItemId
+ Lorentz: DocItemInDefinitions :: DocItemPlacementKind
+ Lorentz: DocItemInlined :: DocItemPlacementKind
+ Lorentz: DocSectionNameBig :: DocSectionNameStyle
+ Lorentz: DocSectionNameSmall :: DocSectionNameStyle
+ Lorentz: EpAddress :: Address -> EpName -> EpAddress
+ Lorentz: ErrClassActionException :: ErrorClass
+ Lorentz: ErrClassBadArgument :: ErrorClass
+ Lorentz: ErrClassContractInternal :: ErrorClass
+ Lorentz: ErrClassUnknown :: ErrorClass
+ Lorentz: False :: Bool
+ Lorentz: FutureContract :: EpAddress -> FutureContract p
+ Lorentz: GitRepoSettings :: (Text -> Text) -> GitRepoSettings
+ Lorentz: Just :: a -> Maybe a
+ Lorentz: Left :: a -> Either a b
+ Lorentz: LorentzInstr :: RemFail Instr (ToTs inp) (ToTs out) -> (:->)
+ Lorentz: MigrationScript :: Lambda UStore_ UStore_ -> MigrationScript
+ Lorentz: NamedField :: Symbol -> Type -> NamedField
+ Lorentz: NoSuchEntryPoint :: MText -> EntryPointLookupError
+ Lorentz: Nothing :: Maybe a
+ Lorentz: ParamBuildingStep :: Markdown -> (CurrentParam -> Markdown) -> (CurrentParam -> Markdown) -> ParamBuildingStep
+ Lorentz: ParameterEntryPointsSplit :: Notes (ToT p) -> ParameterEntryPointsSplit p
+ Lorentz: Proxy :: Proxy
+ Lorentz: Right :: b -> Either a b
+ Lorentz: StoreFieldOps :: (forall s. Label fname -> (store : s) :-> (ftype : s)) -> (forall s. Label fname -> (ftype : (store : s)) :-> (store : s)) -> StoreFieldOps store fname ftype
+ Lorentz: StoreSubmapOps :: (forall s. Label mname -> (key : (store : s)) :-> (Bool : s)) -> (forall s. Label mname -> (key : (store : s)) :-> (Maybe value : s)) -> (forall s. Label mname -> (key : (Maybe value : (store : s))) :-> (store : s)) -> (forall s. Maybe (Label mname -> (key : (store : s)) :-> (store : s))) -> (forall s. Maybe (Label mname -> (key : (value : (store : s))) :-> (store : s))) -> StoreSubmapOps store mname key value
+ Lorentz: SubDoc :: DocBlock -> SubDoc
+ Lorentz: True :: Bool
+ Lorentz: UParamUnsafe :: (MText, ByteString) -> UParam
+ Lorentz: UStoreField :: v -> UStoreFieldExt
+ Lorentz: UStoreSubMap :: Map k v -> (|~>) k v
+ Lorentz: UnspecifiedError :: UnspecifiedError
+ Lorentz: View :: a -> ContractRef r -> View
+ Lorentz: VoidResult :: r -> VoidResult r
+ Lorentz: Void_ :: a -> Lambda b b -> Void_
+ Lorentz: [:&] :: forall u (a :: u -> Type) (b :: [u]) (r :: u) (rs :: [u]). () => !a r -> !Rec a rs -> Rec a (r : rs)
+ Lorentz: [CaseClauseL] :: (AppendCtorField x inp :-> out) -> CaseClauseL inp out ( 'CaseClauseParam ctor x)
+ Lorentz: [ConstrainedSome] :: c a => a -> ConstrainedSome c
+ Lorentz: [CvAddress] :: EpAddress -> CValue 'CAddress
+ Lorentz: [CvBool] :: Bool -> CValue 'CBool
+ Lorentz: [CvBytes] :: ByteString -> CValue 'CBytes
+ Lorentz: [CvInt] :: Integer -> CValue 'CInt
+ Lorentz: [CvKeyHash] :: KeyHash -> CValue 'CKeyHash
+ Lorentz: [CvMutez] :: Mutez -> CValue 'CMutez
+ Lorentz: [CvNat] :: Natural -> CValue 'CNat
+ Lorentz: [CvString] :: MText -> CValue 'CString
+ Lorentz: [CvTimestamp] :: Timestamp -> CValue 'CTimestamp
+ Lorentz: [DError] :: IsError e => Proxy e -> DError
+ Lorentz: [DThrows] :: IsError e => Proxy e -> DThrows
+ Lorentz: [DType] :: TypeHasDoc a => Proxy a -> DType
+ Lorentz: [DocItemNoRef] :: DocItemRef 'DocItemInlined
+ Lorentz: [DocItemRef] :: DocItemId -> DocItemRef 'DocItemInDefinitions
+ Lorentz: [Holds] :: Condition s (Bool : s) s s
+ Lorentz: [IsCons] :: Condition s ([a] : s) (a : ([a] : s)) s
+ Lorentz: [IsEq] :: IfCmpXConstraints a Eq' => Condition s (a : (a : s)) s s
+ Lorentz: [IsGe] :: IfCmpXConstraints a Ge => Condition s (a : (a : s)) s s
+ Lorentz: [IsGt] :: IfCmpXConstraints a Gt => Condition s (a : (a : s)) s s
+ Lorentz: [IsLe] :: IfCmpXConstraints a Le => Condition s (a : (a : s)) s s
+ Lorentz: [IsLeft] :: Condition s (Either l r : s) (l : s) (r : s)
+ Lorentz: [IsLt] :: IfCmpXConstraints a Lt => Condition s (a : (a : s)) s s
+ Lorentz: [IsNeq] :: IfCmpXConstraints a Neq => Condition s (a : (a : s)) s s
+ Lorentz: [IsNil] :: Condition s ([a] : s) s (a : ([a] : s))
+ Lorentz: [IsNone] :: Condition s (Maybe a : s) s (a : s)
+ Lorentz: [IsNotZero] :: (UnaryArithOpHs Eq' a, UnaryArithResHs Eq' a ~ Bool) => Condition s (a : s) s s
+ Lorentz: [IsRight] :: Condition s (Either l r : s) (r : s) (l : s)
+ Lorentz: [IsSome] :: Condition s (Maybe a : s) (a : s) s
+ Lorentz: [IsZero] :: (UnaryArithOpHs Eq' a, UnaryArithResHs Eq' a ~ Bool) => Condition s (a : s) s s
+ Lorentz: [RNil] :: forall u (a :: u -> Type) (b :: [u]). () => Rec a ([] :: [u])
+ Lorentz: [SomeContract] :: (NiceParameter cp, NiceStorage st) => Contract cp st -> SomeContract
+ Lorentz: [SomeDocDefinitionItem] :: (DocItem d, DocItemPlacement d ~ 'DocItemInDefinitions) => d -> SomeDocDefinitionItem
+ Lorentz: [SomeDocItem] :: DocItem d => d -> SomeDocItem
+ Lorentz: [SomeTypeWithDoc] :: TypeHasDoc td => Proxy td -> SomeTypeWithDoc
+ Lorentz: [cdContents] :: ContractDoc -> DocBlock
+ Lorentz: [cdDefinitionIds] :: ContractDoc -> Set DocItemId
+ Lorentz: [cdDefinitionsSet] :: ContractDoc -> Set SomeDocDefinitionItem
+ Lorentz: [cdDefinitions] :: ContractDoc -> DocBlock
+ Lorentz: [ceArg] :: CustomError -> ErrorArg tag
+ Lorentz: [ceTag] :: CustomError -> Label tag
+ Lorentz: [crAddress] :: ContractRef -> Address
+ Lorentz: [crEntryPoint] :: ContractRef -> SomeEntryPointCall arg
+ Lorentz: [dgrCommitDate] :: DGitRevision -> Text
+ Lorentz: [dgrCommitSha] :: DGitRevision -> Text
+ Lorentz: [dgrRepoSettings] :: DGitRevision -> GitRepoSettings
+ Lorentz: [eaAddress] :: EpAddress -> Address
+ Lorentz: [eaEntryPoint] :: EpAddress -> EpName
+ Lorentz: [epaArg] :: DEntryPointArg -> Maybe DType
+ Lorentz: [epaBuilding] :: DEntryPointArg -> [ParamBuildingStep]
+ Lorentz: [futureContractAddress] :: FutureContract p -> EpAddress
+ Lorentz: [grsMkGitRevision] :: GitRepoSettings -> Text -> Text
+ Lorentz: [pbsEnglish] :: ParamBuildingStep -> Markdown
+ Lorentz: [pbsHaskell] :: ParamBuildingStep -> CurrentParam -> Markdown
+ Lorentz: [pbsMichelson] :: ParamBuildingStep -> CurrentParam -> Markdown
+ Lorentz: [pesNotes] :: ParameterEntryPointsSplit p -> Notes (ToT p)
+ Lorentz: [sopDelete] :: StoreSubmapOps store mname key value -> forall s. Maybe (Label mname -> (key : (store : s)) :-> (store : s))
+ Lorentz: [sopGet] :: StoreSubmapOps store mname key value -> forall s. Label mname -> (key : (store : s)) :-> (Maybe value : s)
+ Lorentz: [sopInsert] :: StoreSubmapOps store mname key value -> forall s. Maybe (Label mname -> (key : (value : (store : s))) :-> (store : s))
+ Lorentz: [sopMem] :: StoreSubmapOps store mname key value -> forall s. Label mname -> (key : (store : s)) :-> (Bool : s)
+ Lorentz: [sopSetField] :: StoreFieldOps store fname ftype -> forall s. Label fname -> (ftype : (store : s)) :-> (store : s)
+ Lorentz: [sopToField] :: StoreFieldOps store fname ftype -> forall s. Label fname -> (store : s) :-> (ftype : s)
+ Lorentz: [sopUpdate] :: StoreSubmapOps store mname key value -> forall s. Label mname -> (key : (Maybe value : (store : s))) :-> (store : s)
+ Lorentz: [unBigMap] :: BigMap k v -> Map k v
+ Lorentz: [unLorentzInstr] :: (:->) -> RemFail Instr (ToTs inp) (ToTs out)
+ Lorentz: [unMigrationScript] :: MigrationScript -> Lambda UStore_ UStore_
+ Lorentz: [unUStoreField] :: UStoreFieldExt -> v
+ Lorentz: [unUStoreSubMap] :: (|~>) k v -> Map k v
+ Lorentz: [unVoidResult] :: VoidResult r -> r
+ Lorentz: [viewCallbackTo] :: View -> ContractRef r
+ Lorentz: [viewParam] :: View -> a
+ Lorentz: [voidParam] :: Void_ -> a
+ Lorentz: [voidResProxy] :: Void_ -> Lambda b b
+ Lorentz: _Wrapped' :: Wrapped s => Iso' s (Unwrapped s)
+ Lorentz: abs :: UnaryArithOpHs Abs n => (n & s) :-> (UnaryArithResHs Abs n & s)
+ Lorentz: add :: ArithOpHs Add n m => (n & (m & s)) :-> (ArithResHs Add n m & s)
+ Lorentz: addNewErrorTags :: ErrorTagMap -> HashSet MText -> ErrorTagMap
+ Lorentz: address :: (ContractRef a & s) :-> (Address & s)
+ Lorentz: amount :: s :-> (Mutez & s)
+ Lorentz: analyzeLorentz :: (inp :-> out) -> AnalyzerRes
+ Lorentz: and :: ArithOpHs And n m => (n & (m & s)) :-> (ArithResHs And n m & s)
+ Lorentz: apply :: forall a b c s. NiceConstant a => (a & (Lambda (a, b) c & s)) :-> (Lambda b c & s)
+ Lorentz: applyErrorTagMap :: HasCallStack => ErrorTagMap -> (inp :-> out) -> inp :-> out
+ Lorentz: arg :: () => Name name -> (name :! a) -> a
+ Lorentz: argDef :: () => Name name -> a -> (name :? a) -> a
+ Lorentz: argF :: () => Name name -> NamedF f a name -> f a
+ Lorentz: assert :: IsError err => err -> (Bool & s) :-> s
+ Lorentz: assertEq :: (IfCmpXConstraints a Eq', IsError err) => err -> (a & (a & s)) :-> s
+ Lorentz: assertEq0 :: (IfCmp0Constraints a Eq', IsError err) => err -> (a & s) :-> s
+ Lorentz: assertGe :: (IfCmpXConstraints a Ge, IsError err) => err -> (a & (a & s)) :-> s
+ Lorentz: assertGe0 :: (IfCmp0Constraints a Ge, IsError err) => err -> (a & s) :-> s
+ Lorentz: assertGt :: (IfCmpXConstraints a Gt, IsError err) => err -> (a & (a & s)) :-> s
+ Lorentz: assertGt0 :: (IfCmp0Constraints a Gt, IsError err) => err -> (a & s) :-> s
+ Lorentz: assertLe :: (IfCmpXConstraints a Le, IsError err) => err -> (a & (a & s)) :-> s
+ Lorentz: assertLe0 :: (IfCmp0Constraints a Le, IsError err) => err -> (a & s) :-> s
+ Lorentz: assertLeft :: IsError err => err -> (Either a b & s) :-> (a & s)
+ Lorentz: assertLt :: (IfCmpXConstraints a Lt, IsError err) => err -> (a & (a & s)) :-> s
+ Lorentz: assertLt0 :: (IfCmp0Constraints a Lt, IsError err) => err -> (a & s) :-> s
+ Lorentz: assertNeq :: (IfCmpXConstraints a Neq, IsError err) => err -> (a & (a & s)) :-> s
+ Lorentz: assertNeq0 :: (IfCmp0Constraints a Neq, IsError err) => err -> (a & s) :-> s
+ Lorentz: assertNone :: IsError err => err -> (Maybe a & s) :-> s
+ Lorentz: assertRight :: IsError err => err -> (Either a b & s) :-> (b & s)
+ Lorentz: assertSome :: IsError err => err -> (Maybe a & s) :-> (a & s)
+ Lorentz: assertUsing :: IsError a => a -> (Bool & s) :-> s
+ Lorentz: balance :: s :-> (Mutez & s)
+ Lorentz: blake2B :: (ByteString & s) :-> (ByteString & s)
+ Lorentz: buildErrorTagMap :: HashSet MText -> ErrorTagMap
+ Lorentz: buildLorentzDoc :: (inp :-> out) -> ContractDoc
+ Lorentz: buildView :: (a -> Builder) -> View a r -> Builder
+ Lorentz: buildViewTuple :: TupleF a => View a r -> Builder
+ Lorentz: caar :: (((a, b1), b2) & s) :-> (a & s)
+ Lorentz: cadr :: (((a, b1), b2) & s) :-> (b1 & s)
+ Lorentz: car :: ((a, b) & s) :-> (a & s)
+ Lorentz: caseT :: forall dt out inp clauses. CaseTC dt out inp clauses => IsoRecTuple clauses -> (dt & inp) :-> out
+ Lorentz: caseUParam :: (CaseUParam entries, RequireUniqueEntryPoints entries) => Rec (CaseClauseU inp out) entries -> UParamFallback inp out -> (UParam entries : inp) :-> out
+ Lorentz: caseUParamT :: forall entries inp out clauses. (clauses ~ Rec (CaseClauseU inp out) entries, RecFromTuple clauses, CaseUParam entries) => IsoRecTuple clauses -> UParamFallback inp out -> (UParam entries : inp) :-> out
+ Lorentz: case_ :: forall dt out inp. (InstrCaseC dt inp out, RMap (CaseClauses dt)) => Rec (CaseClauseL inp out) (CaseClauses dt) -> (dt & inp) :-> out
+ Lorentz: cast :: KnownValue a => (a & s) :-> (a & s)
+ Lorentz: cdar :: ((a1, (a2, b)) & s) :-> (a2 & s)
+ Lorentz: cddr :: ((a1, (a2, b)) & s) :-> (b & s)
+ Lorentz: cdr :: ((a, b) & s) :-> (b & s)
+ Lorentz: chainId :: s :-> (ChainId & s)
+ Lorentz: checkSignature :: (PublicKey & (Signature & (ByteString & s))) :-> (Bool & s)
+ Lorentz: clarifyParamBuildingSteps :: ParamBuildingStep -> (inp :-> out) -> inp :-> out
+ Lorentz: class (ArithOp aop (ToCT n) (ToCT m), IsComparable n, IsComparable m, Typeable (ToCT n), Typeable (ToCT m), ToT (ArithResHs aop n m) ~ 'Tc (ArithRes aop (ToCT n) (ToCT m))) => ArithOpHs (aop :: Type) (n :: Type) (m :: Type) where {
+ Lorentz: class Bounded a
+ Lorentz: class (IsoValue a, HasNoNestedBigMaps (ToT a)) => CanHaveBigMap a
+ Lorentz: class CaseArrow name body clause | clause -> name, clause -> body
+ Lorentz: class CaseUParam (entries :: [EntryPointKind])
+ Lorentz: class (Typeable (ToCT n), IsComparable n, CompareOp (ToCT n)) => CompareOpHs n
+ Lorentz: class ConcatOp (ToT c) => ConcatOpHs c
+ Lorentz: class (KnownSymbol tag, TypeHasDoc (ErrorArg tag), IsError (CustomError tag)) => CustomErrorHasDoc tag
+ Lorentz: class Default a
+ Lorentz: class DeriveCtorFieldDoc (cf :: CtorField)
+ Lorentz: class (Typeable d, DOrd d, KnownNat (DocItemPosition d)) => DocItem d where {
+ Lorentz: class (EDivOp (ToCT n) (ToCT m), IsComparable n, IsComparable m, ToT (EDivOpResHs n m) ~ 'Tc (EDivOpRes (ToCT n) (ToCT m)), ToT (EModOpResHs n m) ~ 'Tc (EModOpRes (ToCT n) (ToCT m))) => EDivOpHs n m where {
+ Lorentz: class Eq a
+ Lorentz: class ErrorHasDoc e
+ Lorentz: class FromContractRef (cp :: Type) (contract :: Type)
+ Lorentz: class Generic a
+ Lorentz: class (GetOp (ToT c), ToT (GetOpKeyHs c) ~ 'Tc (GetOpKey (ToT c)), ToT (GetOpValHs c) ~ GetOpVal (ToT c)) => GetOpHs c where {
+ Lorentz: class HaveCommonTypeCtor a b
+ Lorentz: class (Typeable e, ErrorHasDoc e) => IsError e
+ Lorentz: class IsHomomorphic a
+ Lorentz: class IsoCValue a where {
+ Lorentz: class IsoValue a where {
+ Lorentz: class (IterOp (ToT c), ToT (IterOpElHs c) ~ IterOpEl (ToT c)) => IterOpHs c where {
+ Lorentz: class (IsoValue a, Typeable (ToCT a), SingI (ToCT a)) => KnownCValue a
+ Lorentz: class KnownUStoreMarker (marker :: UStoreMarkerType) where {
+ Lorentz: class (IsoValue a, Typeable (ToT a), SingI (ToT a)) => KnownValue a
+ Lorentz: class LorentzFunctor (c :: Type -> Type)
+ Lorentz: class (MapOp (ToT c), ToT (MapOpInpHs c) ~ MapOpInp (ToT c), ToT (MapOpResHs c ()) ~ MapOpRes (ToT c) (ToT ())) => MapOpHs c where {
+ Lorentz: class (MemOp (ToT c), ToT (MemOpKeyHs c) ~ 'Tc (MemOpKey (ToT c))) => MemOpHs c where {
+ Lorentz: class Semigroup a => Monoid a
+ Lorentz: class (IsoValue a, ForbidBigMap (ToT a)) => NoBigMap a
+ Lorentz: class (IsoValue a, ForbidContract (ToT a)) => NoContractType a
+ Lorentz: class (IsoValue a, ForbidOp (ToT a)) => NoOperation a
+ Lorentz: class Eq a => Ord a
+ Lorentz: class NiceParameter p => ParameterEntryPoints p
+ Lorentz: class Semigroup a
+ Lorentz: class SizeOp (ToT c) => SizeOpHs c
+ Lorentz: class SliceOp (ToT c) => SliceOpHs c
+ Lorentz: class StoreHasField store fname ftype | store fname -> ftype
+ Lorentz: class StoreHasSubmap store mname key value | store mname -> key value
+ Lorentz: class ToAddress a
+ Lorentz: class ToContractRef (cp :: Type) (contract :: Type)
+ Lorentz: class Typeable a => TypeHasDoc a
+ Lorentz: class (Generic template, GUStoreConversible (Rep template)) => UStoreConversible template
+ Lorentz: class (UnaryArithOp aop (ToCT n), IsComparable n, Typeable (ToCT n), ToT (UnaryArithResHs aop n) ~ 'Tc (UnaryArithRes aop (ToCT n))) => UnaryArithOpHs (aop :: Type) (n :: Type) where {
+ Lorentz: class UnpackUParam (c :: Type -> Constraint) entries
+ Lorentz: class (UpdOp (ToT c), ToT (UpdOpKeyHs c) ~ 'Tc (UpdOpKey (ToT c)), ToT (UpdOpParamsHs c) ~ UpdOpParams (ToT c)) => UpdOpHs c where {
+ Lorentz: class Wrapped s where {
+ Lorentz: cloneX :: forall (n :: Nat) a s. CloneX (ToPeano n) a s => (a & s) :-> CloneXT (ToPeano n) a s
+ Lorentz: coerceContractRef :: ToT a ~ ToT b => ContractRef a -> ContractRef b
+ Lorentz: coerceUnwrap :: Coercible_ newtyp (Unwrapped newtyp) => (newtyp : s) :-> (Unwrapped newtyp : s)
+ Lorentz: coerceWrap :: Coercible_ newtyp (Unwrapped newtyp) => (Unwrapped newtyp : s) :-> (newtyp : s)
+ Lorentz: coerce_ :: Coercible_ a b => (a & s) :-> (b & s)
+ Lorentz: compare :: ArithOpHs Compare n n => (n & (n & s)) :-> (ArithResHs Compare n n & s)
+ Lorentz: compileLorentz :: (inp :-> out) -> Instr (ToTs inp) (ToTs out)
+ Lorentz: compileLorentzContract :: forall cp st. (NiceParameter cp, NiceStorage st, ParameterEntryPoints cp) => Contract cp st -> FullContract (ToT cp) (ToT st)
+ Lorentz: composeStoreFieldOps :: Label nameInStore -> StoreFieldOps store nameInStore substore -> StoreFieldOps substore nameInSubstore field -> StoreFieldOps store nameInSubstore field
+ Lorentz: composeStoreSubmapOps :: Label nameInStore -> StoreFieldOps store nameInStore substore -> StoreSubmapOps substore mname key value -> StoreSubmapOps store mname key value
+ Lorentz: concat :: ConcatOpHs c => (c & (c & s)) :-> (c & s)
+ Lorentz: concat' :: ConcatOpHs c => (List c & s) :-> (c & s)
+ Lorentz: concreteTypeDocHaskellRep :: forall a b. (Typeable a, IsoValue a, Generic a, GTypeHasDoc (Rep a), HaveCommonTypeCtor b a) => TypeDocHaskellRep b
+ Lorentz: concreteTypeDocHaskellRepUnsafe :: forall a b. (Typeable a, IsoValue a, Generic a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep b
+ Lorentz: concreteTypeDocMichelsonRep :: forall a b. (Typeable a, SingI (ToT a), HaveCommonTypeCtor b a) => TypeDocMichelsonRep b
+ Lorentz: concreteTypeDocMichelsonRepUnsafe :: forall a b. (Typeable a, SingI (ToT a)) => TypeDocMichelsonRep b
+ Lorentz: cons :: (a & (List a & s)) :-> (List a & s)
+ Lorentz: construct :: forall dt st. (InstrConstructC dt, RMap (ConstructorFieldTypes dt)) => Rec (FieldConstructor st) (ConstructorFieldTypes dt) -> st :-> (dt & st)
+ Lorentz: constructT :: forall dt fctors st. (InstrConstructC dt, RMap (ConstructorFieldTypes dt), fctors ~ Rec (FieldConstructor st) (ConstructorFieldTypes dt), RecFromTuple fctors) => IsoRecTuple fctors -> st :-> (dt & st)
+ Lorentz: contract :: forall p s. NiceParameter p => (Address & s) :-> (Maybe (ContractRef p) & s)
+ Lorentz: contractDocToMarkdown :: ContractDoc -> LText
+ Lorentz: contractName :: Text -> (inp :-> out) -> inp :-> out
+ Lorentz: convertContractRef :: forall cp contract2 contract1. (ToContractRef cp contract1, FromContractRef cp contract2) => contract1 -> contract2
+ Lorentz: createContract :: forall p g s. (NiceStorage g, ParameterEntryPoints p) => Contract p g -> (Maybe KeyHash & (Mutez & (g & s))) :-> (Operation & (Address & s))
+ Lorentz: customErrArgumentSemantics :: CustomErrorHasDoc tag => Maybe Markdown
+ Lorentz: customErrClass :: CustomErrorHasDoc tag => ErrorClass
+ Lorentz: customErrDocMdCause :: CustomErrorHasDoc tag => Markdown
+ Lorentz: customErrDocMdCauseInEntrypoint :: CustomErrorHasDoc tag => Markdown
+ Lorentz: customErrorFromVal :: forall t e. (SingI t, LooseSumC e) => Value t -> Either Text e
+ Lorentz: customErrorToVal :: (LooseSumC e, HasCallStack) => e -> (forall t. ErrorScope t => Value t -> r) -> r
+ Lorentz: customTypeDocMdReference :: (Text, DType) -> [DType] -> WithinParens -> Markdown
+ Lorentz: cutLorentzNonDoc :: (inp :-> out) -> s :-> s
+ Lorentz: data Address
+ Lorentz: data Bool
+ Lorentz: data ByteString
+ Lorentz: data CValue t
+ Lorentz: data CaseClauseL (inp :: [Type]) (out :: [Type]) (param :: CaseClauseParam)
+ Lorentz: data ChainId
+ Lorentz: data Condition st arg argl argr
+ Lorentz: data ConstrainedSome (c :: Type -> Constraint)
+ Lorentz: data ContractDoc
+ Lorentz: data ContractRef (arg :: Type)
+ Lorentz: data CustomError (tag :: Symbol)
+ Lorentz: data DComment
+ Lorentz: data DDescription
+ Lorentz: data DEntryPoint (kind :: Type)
+ Lorentz: data DEntryPointArg
+ Lorentz: data DError
+ Lorentz: data DGitRevision
+ Lorentz: data DThrows
+ Lorentz: data DType
+ Lorentz: data DVersion
+ Lorentz: data DocItemPlacementKind
+ Lorentz: data DocItemRef (p :: DocItemPlacementKind)
+ Lorentz: data DocSectionNameStyle
+ Lorentz: data Either a b
+ Lorentz: data EntryPointLookupError
+ Lorentz: data EpAddress
+ Lorentz: data ErrorClass
+ Lorentz: data Integer
+ Lorentz: data KeyHash
+ Lorentz: data MText
+ Lorentz: data Map k a
+ Lorentz: data Maybe a
+ Lorentz: data Mutez
+ Lorentz: data NamedField
+ Lorentz: data Natural
+ Lorentz: data ParamBuildingStep
+ Lorentz: data PlainEntryPointsKind
+ Lorentz: data PublicKey
+ Lorentz: data Set a
+ Lorentz: data Signature
+ Lorentz: data SomeContract
+ Lorentz: data SomeDocDefinitionItem
+ Lorentz: data SomeDocItem
+ Lorentz: data SomeTypeWithDoc
+ Lorentz: data StoreFieldOps store fname ftype
+ Lorentz: data StoreSubmapOps store mname key value
+ Lorentz: data Text
+ Lorentz: data Timestamp
+ Lorentz: data UStore (a :: Type)
+ Lorentz: data UStoreMigration (oldStore :: Type) (newStore :: Type)
+ Lorentz: data UnspecifiedError
+ Lorentz: data View (a :: Type) (r :: Type)
+ Lorentz: data Void_ (a :: Type) (b :: Type)
+ Lorentz: data k ~> v
+ Lorentz: data Rec (a :: u -> Type) (b :: [u]) :: forall u. () => u -> Type -> [u] -> Type
+ Lorentz: def :: Default a => a
+ Lorentz: deleteMap :: forall k v s. (MapInstrs map, IsComparable k, KnownValue k, KnownValue v) => (k : (map k v : s)) :-> (map k v : s)
+ Lorentz: deriveCtorFieldDoc :: DeriveCtorFieldDoc cf => Maybe DType
+ Lorentz: deriveCustomError :: Name -> Q [Dec]
+ Lorentz: diEntryPointToMarkdown :: HeaderLevel -> DEntryPoint level -> Markdown
+ Lorentz: dig :: forall (n :: Nat) inp out a. ConstraintDIGLorentz (ToPeano n) inp out a => inp :-> out
+ Lorentz: digPeano :: forall (n :: Peano) inp out a. ConstraintDIGLorentz n inp out a => inp :-> out
+ Lorentz: dip :: forall a s s'. HasCallStack => (s :-> s') -> (a & s) :-> (a & s')
+ Lorentz: dipN :: forall (n :: Nat) (inp :: [Type]) (out :: [Type]) (s :: [Type]) (s' :: [Type]). ConstraintDIPNLorentz (ToPeano n) inp out s s' => (s :-> s') -> inp :-> out
+ Lorentz: dipNPeano :: forall (n :: Peano) (inp :: [Type]) (out :: [Type]) (s :: [Type]) (s' :: [Type]). ConstraintDIPNLorentz n inp out s s' => (s :-> s') -> inp :-> out
+ Lorentz: dipT :: forall a inp dinp dout out. DipT inp a inp dinp dout out => (dinp :-> dout) -> inp :-> out
+ Lorentz: doc :: DocItem di => di -> s :-> s
+ Lorentz: docDefinitionRef :: (DocItem d, DocItemPlacement d ~ 'DocItemInDefinitions) => Markdown -> d -> Markdown
+ Lorentz: docGroup :: DocGrouping -> (inp :-> out) -> inp :-> out
+ Lorentz: docItemDependencies :: DocItem d => d -> [SomeDocDefinitionItem]
+ Lorentz: docItemPosition :: forall d. DocItem d => DocItemPos
+ Lorentz: docItemRef :: (DocItem d, DocItemPlacement d ~ 'DocItemInlined) => d -> DocItemRef (DocItemPlacement d)
+ Lorentz: docItemSectionDescription :: DocItem d => Maybe Markdown
+ Lorentz: docItemSectionName :: DocItem d => Maybe Text
+ Lorentz: docItemSectionNameStyle :: DocItem d => DocSectionNameStyle
+ Lorentz: docItemToMarkdown :: DocItem d => HeaderLevel -> d -> Markdown
+ Lorentz: docItemsOrder :: DocItem d => [d] -> [d]
+ Lorentz: drop :: (a & s) :-> s
+ Lorentz: dropN :: forall (n :: Nat) (s :: [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
+ Lorentz: dropT :: forall a inp dinp dout out. (DipT inp a inp dinp dout out, dinp ~ (a : dout)) => inp :-> out
+ Lorentz: dropX :: forall (n :: Nat) a inp out s s'. (ConstraintDIPNLorentz (ToPeano n) inp out s s', s ~ (a : s')) => inp :-> out
+ Lorentz: dug :: forall (n :: Nat) inp out a. ConstraintDUGLorentz (ToPeano n) inp out a => inp :-> out
+ Lorentz: dup :: (a & s) :-> (a & (a & s))
+ Lorentz: dupT :: forall a st. DupT st a st => st :-> (a : st)
+ Lorentz: duupX :: forall (n :: Nat) a (s :: [Type]) (s1 :: [Type]) (tail :: [Type]). (ConstraintDuupXLorentz (ToPeano (n - 1)) s a s1 tail, DuupX (ToPeano n) s a s1 tail) => s :-> (a : s)
+ Lorentz: ediv :: EDivOpHs n m => (n & (m & s)) :-> (Maybe (EDivOpResHs n m, EModOpResHs n m) & s)
+ Lorentz: embodyFutureContract :: forall arg. (NiceParameter arg, HasCallStack) => FutureContract arg -> ContractRef arg
+ Lorentz: emptyBigMap :: (KnownCValue k, KnownValue v) => s :-> (BigMap k v & s)
+ Lorentz: emptyMap :: (KnownCValue k, KnownValue v) => s :-> (Map k v & s)
+ Lorentz: emptySet :: KnownCValue e => s :-> (Set e & s)
+ Lorentz: entryCase :: forall dt entryPointKind out inp clauses. (CaseTC dt out inp clauses, DocumentEntryPoints entryPointKind dt) => Proxy entryPointKind -> IsoRecTuple clauses -> (dt & inp) :-> out
+ Lorentz: eq :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Eq' (ArithResHs Compare n n) & s)
+ Lorentz: eq0 :: UnaryArithOpHs Eq' n => (n & s) :-> (UnaryArithResHs Eq' n & s)
+ Lorentz: error :: HasCallStack => Text -> a
+ Lorentz: errorDocClass :: ErrorHasDoc e => ErrorClass
+ Lorentz: errorDocDependencies :: ErrorHasDoc e => [SomeDocDefinitionItem]
+ Lorentz: errorDocHaskellRep :: ErrorHasDoc e => Markdown
+ Lorentz: errorDocMdCause :: ErrorHasDoc e => Markdown
+ Lorentz: errorDocMdCauseInEntrypoint :: ErrorHasDoc e => Markdown
+ Lorentz: errorDocName :: ErrorHasDoc e => Text
+ Lorentz: errorFromVal :: (IsError e, Typeable t, SingI t) => Value t -> Either Text e
+ Lorentz: errorFromValNumeric :: (Typeable t, SingI t, IsError e) => ErrorTagMap -> Value t -> Either Text e
+ Lorentz: errorToVal :: IsError e => e -> (forall t. ErrorScope t => Value t -> r) -> r
+ Lorentz: errorsDocumentation :: Markdown
+ Lorentz: exec :: (a & (Lambda a b & s)) :-> (b & s)
+ Lorentz: execute :: forall i o s. Each [KnownList, ZipInstr] [i, o] => ((i :-> o) : (i ++ s)) :-> (o ++ s)
+ Lorentz: failCustom :: forall tag err s any. (err ~ ErrorArg tag, CustomErrorHasDoc tag, KnownError err) => Label tag -> (err : s) :-> any
+ Lorentz: failCustom_ :: forall tag s any notVoidError. (TypeErrorUnless (ErrorArg tag == ()) notVoidError, CustomErrorHasDoc tag, notVoidError ~ ( 'Text "Expected no-arg error, but given error requires argument of type " :<>: 'ShowType (ErrorArg tag))) => Label tag -> s :-> any
+ Lorentz: failUnexpected :: MText -> s :-> t
+ Lorentz: failUsing :: forall e s t. IsError e => e -> s :-> t
+ Lorentz: failUsingArg :: forall err name fieldTy s s'. FailUsingArg err name fieldTy s s'
+ Lorentz: failWith :: KnownValue a => (a & s) :-> t
+ Lorentz: fail_ :: a :-> c
+ Lorentz: 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
+ Lorentz: fakeCoerce :: s1 :-> s2
+ Lorentz: fieldCtor :: HasCallStack => (st :-> (f & st)) -> FieldConstructor st f
+ Lorentz: fillUStore :: UStoreConversible template => template -> UStoreMigrationT () template
+ Lorentz: framed :: forall s i o. (KnownList i, KnownList o) => (i :-> o) -> (i ++ s) :-> (o ++ s)
+ Lorentz: framedN :: forall n nNat s i i' o o'. (nNat ~ ToPeano n, i' ~ Take nNat i, s ~ Drop nNat i, i ~ (i' ++ s), o ~ (o' ++ s), KnownList i', KnownList o') => (i' :-> o') -> i :-> o
+ Lorentz: fromCVal :: IsoCValue a => CValue (ToCT a) -> a
+ Lorentz: fromContractAddr :: FromContractRef cp contract => ContractRef cp -> contract
+ Lorentz: fromInteger :: Num a => Integer -> a
+ Lorentz: fromLabel :: IsLabel x a => a
+ Lorentz: fromNamed :: Label name -> (NamedF Identity a name : s) :-> (a : s)
+ Lorentz: fromString :: IsString a => String -> a
+ Lorentz: fromVal :: (IsoValue a, Generic a, GIsoValue (Rep a), ToT a ~ GValueType (Rep a)) => Value (ToT a) -> a
+ Lorentz: futureContract :: (Address : s) :-> (FutureContract p : s)
+ Lorentz: gatherErrorTags :: (inp :-> out) -> HashSet MText
+ Lorentz: gcoerce_ :: Coercible_ (t a) (t b) => (t a : s) :-> (t b : s)
+ Lorentz: ge :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Ge (ArithResHs Compare n n) & s)
+ Lorentz: ge0 :: UnaryArithOpHs Ge n => (n & s) :-> (UnaryArithResHs Ge n & s)
+ Lorentz: genericTypeDocDependencies :: forall a. (Generic a, GTypeHasDoc (Rep a)) => Proxy a -> [SomeTypeWithDoc]
+ Lorentz: get :: GetOpHs c => (GetOpKeyHs c & (c & s)) :-> (Maybe (GetOpValHs c) & s)
+ Lorentz: getField :: forall dt name st. InstrGetFieldC dt name => Label name -> (dt & st) :-> (GetFieldType dt name & (dt : st))
+ Lorentz: getFieldNamed :: forall dt name st. InstrGetFieldC dt name => Label name -> (dt & st) :-> ((name :! GetFieldType dt name) & (dt : st))
+ Lorentz: gt :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Gt (ArithResHs Compare n n) & s)
+ Lorentz: gt0 :: UnaryArithOpHs Gt n => (n & s) :-> (UnaryArithResHs Gt n & s)
+ Lorentz: hashKey :: (PublicKey & s) :-> (KeyHash & s)
+ Lorentz: haskellRepNoFields :: TypeDocHaskellRep a -> TypeDocHaskellRep a
+ Lorentz: haskellRepStripFieldPrefix :: HasCallStack => TypeDocHaskellRep a -> TypeDocHaskellRep a
+ Lorentz: homomorphicTypeDocHaskellRep :: forall a. (Generic a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep a
+ Lorentz: homomorphicTypeDocMdReference :: forall (t :: Type). (Typeable t, TypeHasDoc t, IsHomomorphic t) => Proxy t -> WithinParens -> Markdown
+ Lorentz: homomorphicTypeDocMichelsonRep :: forall a. SingI (ToT a) => TypeDocMichelsonRep a
+ Lorentz: iAnyCode :: (inp :-> out) -> Instr (ToTs inp) (ToTs out)
+ Lorentz: iGenericIf :: (forall s'. Instr (ToTs a) s' -> Instr (ToTs b) s' -> Instr (ToTs c) s') -> (a :-> s) -> (b :-> s) -> c :-> s
+ Lorentz: iMapAnyCode :: (forall o'. Instr (ToTs i1) o' -> Instr (ToTs i2) o') -> (i1 :-> o) -> i2 :-> o
+ Lorentz: iNonFailingCode :: HasCallStack => (inp :-> out) -> Instr (ToTs inp) (ToTs out)
+ Lorentz: ifCons :: ((a & (List a & s)) :-> s') -> (s :-> s') -> (List a & s) :-> s'
+ Lorentz: ifEq :: IfCmpXConstraints a Eq' => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
+ Lorentz: ifEq0 :: IfCmp0Constraints a Eq' => (s :-> s') -> (s :-> s') -> (a & s) :-> s'
+ Lorentz: ifGe :: IfCmpXConstraints a Ge => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
+ Lorentz: ifGe0 :: IfCmp0Constraints a Ge => (s :-> s') -> (s :-> s') -> (a & s) :-> s'
+ Lorentz: ifGt :: IfCmpXConstraints a Gt => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
+ Lorentz: ifGt0 :: IfCmp0Constraints a Gt => (s :-> s') -> (s :-> s') -> (a & s) :-> s'
+ Lorentz: ifLe :: IfCmpXConstraints a Le => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
+ Lorentz: ifLe0 :: IfCmp0Constraints a Le => (s :-> s') -> (s :-> s') -> (a & s) :-> s'
+ Lorentz: ifLeft :: ((a & s) :-> s') -> ((b & s) :-> s') -> (Either a b & s) :-> s'
+ Lorentz: ifLt :: IfCmpXConstraints a Lt => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
+ Lorentz: ifLt0 :: IfCmp0Constraints a Lt => (s :-> s') -> (s :-> s') -> (a & s) :-> s'
+ Lorentz: ifNeq :: IfCmpXConstraints a Neq => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
+ Lorentz: ifNeq0 :: IfCmp0Constraints a Neq => (s :-> s') -> (s :-> s') -> (a & s) :-> s'
+ Lorentz: ifNone :: (s :-> s') -> ((a & s) :-> s') -> (Maybe a & s) :-> s'
+ Lorentz: ifRight :: ((b & s) :-> s') -> ((a & s) :-> s') -> (Either a b & s) :-> s'
+ Lorentz: ifSome :: ((a & s) :-> s') -> (s :-> s') -> (Maybe a & s) :-> s'
+ Lorentz: ifThenElse :: Condition st arg argl argr -> (argl :-> o) -> (argr :-> o) -> arg :-> o
+ Lorentz: if_ :: (s :-> s') -> (s :-> s') -> (Bool & s) :-> s'
+ Lorentz: implicitAccount :: (KeyHash & s) :-> (ContractRef () & s)
+ Lorentz: infix 9 ~>
+ Lorentz: infixl 8 #
+ Lorentz: infixr 0 :=
+ Lorentz: infixr 1 :->
+ Lorentz: infixr 2 &
+ Lorentz: infixr 6 <>
+ Lorentz: infixr 7 :&
+ Lorentz: infixr 9 .
+ Lorentz: int :: (Natural & s) :-> (Integer & s)
+ Lorentz: interpretLorentzInstr :: (IsoValuesStack inp, IsoValuesStack out) => ContractEnv -> (inp :-> out) -> Rec Identity inp -> Either MichelsonFailed (Rec Identity out)
+ Lorentz: interpretLorentzLambda :: (IsoValue inp, IsoValue out) => ContractEnv -> Lambda inp out -> inp -> Either MichelsonFailed out
+ Lorentz: isNat :: (Integer & s) :-> (Maybe Natural & s)
+ Lorentz: isoErrorFromVal :: (Typeable t, Typeable (ToT e), IsoValue e) => Value t -> Either Text e
+ Lorentz: isoErrorToVal :: (KnownError e, IsoValue e) => e -> (forall t. ErrorScope t => Value t -> r) -> r
+ Lorentz: iter :: (IterOpHs c, HasCallStack) => ((IterOpElHs c & s) :-> s) -> (c & s) :-> s
+ Lorentz: lPackValue :: forall a. NicePackedValue a => a -> ByteString
+ Lorentz: lUnpackValue :: forall a. NiceUnpackedValue a => ByteString -> Either UnpackError a
+ Lorentz: lambda :: (ZipInstrs [i, o], KnownValue (ZippedStack i), KnownValue (ZippedStack o)) => (i :-> o) -> s :-> ((i :-> o) & s)
+ Lorentz: le :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Le (ArithResHs Compare n n) & s)
+ Lorentz: le0 :: UnaryArithOpHs Le n => (n & s) :-> (UnaryArithResHs Le n & s)
+ Lorentz: left :: forall a b s. KnownValue b => (a & s) :-> (Either a b & s)
+ Lorentz: liftUStore :: (Generic template, RequireAllUniqueFields template) => Label name -> (UStore (GetFieldType template name) : s) :-> (UStore template : s)
+ Lorentz: lmap :: (LorentzFunctor c, KnownValue b) => ((a : s) :-> (b : s)) -> (c a : s) :-> (c b : s)
+ Lorentz: loop :: (s :-> (Bool & s)) -> (Bool & s) :-> s
+ Lorentz: loopLeft :: ((a & s) :-> (Either a b & s)) -> (Either a b & s) :-> (b & s)
+ Lorentz: lsl :: ArithOpHs Lsl n m => (n & (m & s)) :-> (ArithResHs Lsl n m & s)
+ Lorentz: lsr :: ArithOpHs Lsr n m => (n & (m & s)) :-> (ArithResHs Lsr n m & s)
+ Lorentz: lt :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Lt (ArithResHs Compare n n) & s)
+ Lorentz: lt0 :: UnaryArithOpHs Lt n => (n & s) :-> (UnaryArithResHs Lt n & s)
+ Lorentz: map :: (MapOpHs c, IsoMapOpRes c b, HasCallStack) => ((MapOpInpHs c & s) :-> (b & s)) -> (c & s) :-> (MapOpResHs c b & s)
+ Lorentz: mapCar :: ((a & s) :-> (a1 & s)) -> ((a, b) & s) :-> ((a1, b) & s)
+ Lorentz: mapCdr :: ((b & ((a, b) & s)) :-> (b1 & ((a, b) & s))) -> ((a, b) & s) :-> ((a, b1) & s)
+ Lorentz: mapInsert :: (MapInstrs map, IsComparable k) => (k : (v : (map k v : s))) :-> (map k v : s)
+ Lorentz: mapInsertNew :: (MapInstrs map, IsComparable k, KnownValue e) => (forall s0. (k : s0) :-> (e : s0)) -> (k : (v : (map k v : s))) :-> (map k v : s)
+ Lorentz: mapParameterEntryPoints :: ToT a ~ ToT b => (a -> b) -> ParameterEntryPointsSplit a -> ParameterEntryPointsSplit b
+ Lorentz: mappend :: Monoid a => a -> a -> a
+ Lorentz: maxBound :: Bounded a => a
+ Lorentz: mconcat :: Monoid a => [a] -> a
+ Lorentz: mem :: MemOpHs c => (MemOpKeyHs c & (c & s)) :-> (Bool & s)
+ Lorentz: mempty :: Monoid a => a
+ Lorentz: migrateAddField :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s. ('(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcAdd field diff, HasUField field fieldTy newTempl) => Label field -> (fieldTy : (MUStore oldTempl newTempl diff touched : s)) :-> (MUStore oldTempl newTempl newDiff (field : touched) : s)
+ Lorentz: migrateExtractField :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s. ('(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcRemove field diff, HasUField field fieldTy oldTempl, RequireUntouched field (field `IsElem` touched)) => Label field -> (MUStore oldTempl newTempl diff touched : s) :-> (fieldTy : (MUStore oldTempl newTempl newDiff (field : touched) : s))
+ Lorentz: migrateGetField :: forall field oldTempl newTempl diff touched fieldTy s. (HasUField field fieldTy oldTempl, RequireUntouched field (field `IsElem` touched)) => Label field -> (MUStore oldTempl newTempl diff touched : s) :-> (fieldTy : (MUStore oldTempl newTempl diff touched : s))
+ Lorentz: migrateOverwriteField :: forall field oldTempl newTempl diff touched fieldTy oldFieldTy marker oldMarker newDiff newDiff0 s. ('(UStoreFieldExt oldMarker oldFieldTy, newDiff0) ~ CoverDiff 'DcRemove field diff, '(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcAdd field newDiff0, HasUField field fieldTy newTempl) => Label field -> (fieldTy : (MUStore oldTempl newTempl diff touched : s)) :-> (MUStore oldTempl newTempl newDiff (field : touched) : s)
+ Lorentz: migrateRemoveField :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s. ('(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcRemove field diff, HasUField field fieldTy oldTempl) => Label field -> (MUStore oldTempl newTempl diff touched : s) :-> (MUStore oldTempl newTempl newDiff (field : touched) : s)
+ Lorentz: migrationToLambda :: UStoreMigrationT oldTemplate newTemplate -> Lambda (UStore oldTemplate) (UStore newTemplate)
+ Lorentz: migrationToScript :: UStoreMigration ot nt -> MigrationScript
+ Lorentz: minBound :: Bounded a => a
+ Lorentz: mkDEntryPointArgSimple :: forall t. TypeHasDoc t => DEntryPointArg
+ Lorentz: mkDGitRevision :: Q Exp
+ Lorentz: mkFieldMarkerUKey :: (KnownUStoreMarker marker, KnownSymbol name) => Label name -> ByteString
+ Lorentz: mkUParam :: (KnownSymbol name, NicePackedValue a, LookupEntryPoint name entries ~ a, RequireUniqueEntryPoints entries) => Label name -> a -> UParam entries
+ Lorentz: mkUStore :: UStoreConversible template => template -> UStore template
+ Lorentz: mkUStoreMigration :: Lambda (MUStore oldTempl newTempl (BuildDiff oldTempl newTempl) '[]) (MUStore oldTempl newTempl '[] _1) -> UStoreMigrationT oldTempl newTempl
+ Lorentz: mkView :: ToContractRef r contract => a -> contract -> View a r
+ Lorentz: mkVoid :: forall b a. a -> Void_ a b
+ Lorentz: modifyField :: forall dt name st. (InstrGetFieldC dt name, InstrSetFieldC dt name) => Label name -> (forall st0. (GetFieldType dt name : st0) :-> (GetFieldType dt name : st0)) -> (dt & st) :-> (dt & st)
+ Lorentz: morleyRepoSettings :: GitRepoSettings
+ Lorentz: mt :: QuasiQuoter
+ Lorentz: mul :: ArithOpHs Mul n m => (n & (m & s)) :-> (ArithResHs Mul n m & s)
+ Lorentz: mustoreToOld :: RequireBeInitial touched => (MUStore oldTemplate newTemplate remDiff touched : s) :-> (UStore oldTemplate : s)
+ Lorentz: neg :: UnaryArithOpHs Neg n => (n & s) :-> (UnaryArithResHs Neg n & s)
+ Lorentz: neq :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Neq (ArithResHs Compare n n) & s)
+ Lorentz: neq0 :: UnaryArithOpHs Neq n => (n & s) :-> (UnaryArithResHs Neq n & s)
+ Lorentz: newtype (inp :: [Type]) :-> (out :: [Type])
+ Lorentz: newtype BigMap k v
+ Lorentz: newtype DocItemId
+ Lorentz: newtype FutureContract p
+ Lorentz: newtype GitRepoSettings
+ Lorentz: newtype MigrationScript
+ Lorentz: newtype ParameterEntryPointsSplit p
+ Lorentz: newtype SubDoc
+ Lorentz: newtype UParam (entries :: [EntryPointKind])
+ Lorentz: newtype UStoreFieldExt (m :: UStoreMarkerType) (v :: Type)
+ Lorentz: newtype VoidResult r
+ Lorentz: newtype k |~> v
+ Lorentz: niceConstantEvi :: forall a. NiceConstant a :- ConstantScope (ToT a)
+ Lorentz: nicePackedValueEvi :: forall a. NicePackedValue a :- PackedValScope (ToT a)
+ Lorentz: niceParameterEvi :: forall a. NiceParameter a :- ParameterScope (ToT a)
+ Lorentz: nicePrintedValueEvi :: forall a. NicePrintedValue a :- PrintedValScope (ToT a)
+ Lorentz: niceStorageEvi :: forall a. NiceStorage a :- StorageScope (ToT a)
+ Lorentz: niceUnpackedValueEvi :: forall a. NiceUnpackedValue a :- UnpackedValScope (ToT a)
+ Lorentz: nil :: KnownValue p => s :-> (List p & s)
+ Lorentz: nonZero :: NonZero t => (t : s) :-> (Maybe t : s)
+ Lorentz: none :: forall a s. KnownValue a => s :-> (Maybe a & s)
+ Lorentz: nop :: s :-> s
+ Lorentz: not :: UnaryArithOpHs Not n => (n & s) :-> (UnaryArithResHs Not n & s)
+ Lorentz: now :: s :-> (Timestamp & s)
+ Lorentz: optimizeLorentz :: (inp :-> out) -> inp :-> out
+ Lorentz: optimizeLorentzWithConf :: OptimizerConf -> (inp :-> out) -> inp :-> out
+ Lorentz: or :: ArithOpHs Or n m => (n & (m & s)) :-> (ArithResHs Or n m & s)
+ Lorentz: pack :: forall a s. NicePackedValue a => (a & s) :-> (ByteString & s)
+ Lorentz: pair :: (a & (b & s)) :-> ((a, b) & s)
+ Lorentz: papair :: (a & (b & (c & s))) :-> (((a, b), c) & s)
+ Lorentz: parameterEntryPoints :: ParameterEntryPoints p => ParameterEntryPointsSplit p
+ Lorentz: parseLorentzValue :: forall v. (IsoValue v, SingI (ToT v), Typeable (ToT v)) => Text -> Either ParseLorentzError v
+ Lorentz: pattern FI :: (forall out'. Instr (ToTs inp) out') -> inp :-> out
+ Lorentz: pattern I :: Instr (ToTs inp) (ToTs out) -> inp :-> out
+ Lorentz: pbsUParam :: forall ctorName. KnownSymbol ctorName => ParamBuildingStep
+ Lorentz: pepNone :: SingI (ToT p) => ParameterEntryPointsSplit p
+ Lorentz: pepPlain :: PesEntryPointsC 'False cp st => ParameterEntryPointsSplit cp
+ Lorentz: pepRecursive :: PesEntryPointsC 'True cp st => ParameterEntryPointsSplit cp
+ Lorentz: pickFutureContract :: NiceParameter p => (FutureContract p : s) :-> (Maybe (ContractRef p) : s)
+ Lorentz: poly1TypeDocMdReference :: forall t (r :: Type) (a :: Type). (r ~ t a, Typeable t, Each '[TypeHasDoc] [r, a], IsHomomorphic t) => Proxy r -> WithinParens -> Markdown
+ Lorentz: poly2TypeDocMdReference :: forall t (r :: Type) (a :: Type) (b :: Type). (r ~ t a b, Typeable t, Each '[TypeHasDoc] [r, a, b], IsHomomorphic t) => Proxy r -> WithinParens -> Markdown
+ Lorentz: ppaiir :: (a & (b & (c & s))) :-> ((a, (b, c)) & s)
+ Lorentz: printComment :: PrintComment (ToTs s) -> s :-> s
+ Lorentz: printLorentzContract :: forall cp st. (NiceParameter cp, NiceStorage st, ParameterEntryPoints cp) => Bool -> Contract cp st -> LText
+ Lorentz: printLorentzValue :: forall v. NicePrintedValue v => Bool -> v -> LText
+ Lorentz: pure :: Applicative f => a -> f a
+ Lorentz: push :: forall t s. NiceConstant t => t -> s :-> (t & s)
+ Lorentz: pushContractRef :: NiceParameter arg => (forall s0. (Address : s) :-> s0) -> ContractRef arg -> s :-> (ContractRef arg : s)
+ Lorentz: renderLorentzDoc :: (inp :-> out) -> LText
+ Lorentz: return :: Monad m => a -> m a
+ Lorentz: right :: forall a b s. KnownValue a => (b & s) :-> (Either a b & s)
+ Lorentz: rsub :: ArithOpHs Sub n m => (m & (n & s)) :-> (ArithResHs Sub n m & s)
+ Lorentz: sconcat :: Semigroup a => NonEmpty a -> a
+ Lorentz: self :: forall p s. NiceParameter p => s :-> (ContractRef p & s)
+ Lorentz: sender :: s :-> (Address & s)
+ Lorentz: setCar :: ((a, b1) & (b2 & s)) :-> ((b2, b1) & s)
+ Lorentz: setCdr :: ((a, b1) & (b2 & s)) :-> ((a, b2) & s)
+ Lorentz: setDelegate :: (Maybe KeyHash & s) :-> (Operation & s)
+ Lorentz: setDelete :: IsComparable e => (e & (Set e & s)) :-> (Set e & s)
+ Lorentz: setField :: forall dt name st. InstrSetFieldC dt name => Label name -> (GetFieldType dt name : (dt : st)) :-> (dt : st)
+ Lorentz: setInsert :: IsComparable e => (e & (Set e & s)) :-> (Set e & s)
+ Lorentz: setInsertNew :: (IsComparable e, KnownValue err) => (forall s0. (e : s0) :-> (err : s0)) -> (e & (Set e & s)) :-> (Set e & s)
+ Lorentz: sha256 :: (ByteString & s) :-> (ByteString & s)
+ Lorentz: sha512 :: (ByteString & s) :-> (ByteString & s)
+ Lorentz: size :: SizeOpHs c => (c & s) :-> (Natural & s)
+ Lorentz: slice :: SliceOpHs c => (Natural & (Natural & (c & s))) :-> (Maybe c & s)
+ Lorentz: some :: (a & s) :-> (Maybe a & s)
+ Lorentz: source :: s :-> (Address & s)
+ Lorentz: stDelete :: forall store mname key value s. (StoreHasSubmap store mname key value, KnownValue value) => Label mname -> (key : (store : s)) :-> (store : s)
+ Lorentz: stGet :: StoreHasSubmap store mname key value => Label mname -> (key : (store : s)) :-> (Maybe value : s)
+ Lorentz: stGetField :: StoreHasField store fname ftype => Label fname -> (store : s) :-> (ftype : (store : s))
+ Lorentz: stInsert :: StoreHasSubmap store mname key value => Label mname -> (key : (value : (store : s))) :-> (store : s)
+ Lorentz: stInsertNew :: StoreHasSubmap store mname key value => Label mname -> (forall s0 any. (key : s0) :-> any) -> (key : (value : (store : s))) :-> (store : s)
+ Lorentz: stMem :: StoreHasSubmap store mname key value => Label mname -> (key : (store : s)) :-> (Bool : s)
+ Lorentz: stSetField :: StoreHasField store fname ftype => Label fname -> (ftype : (store : s)) :-> (store : s)
+ Lorentz: stToField :: StoreHasField store fname ftype => Label fname -> (store : s) :-> (ftype : s)
+ Lorentz: stUpdate :: StoreHasSubmap store mname key value => Label mname -> (key : (Maybe value : (store : s))) :-> (store : s)
+ Lorentz: stackRef :: forall (gn :: Nat) st n. (n ~ ToPeano gn, SingI n, KnownPeano n, RequireLongerThan st n) => PrintComment st
+ Lorentz: stackType :: forall s. s :-> s
+ Lorentz: stepsToQuota :: s :-> (Natural & s)
+ Lorentz: stimes :: (Semigroup a, Integral b) => b -> a -> a
+ Lorentz: storeFieldOps :: StoreHasField store fname ftype => StoreFieldOps store fname ftype
+ Lorentz: storeFieldOpsADT :: HasFieldOfType dt fname ftype => StoreFieldOps dt fname ftype
+ Lorentz: storeFieldOpsDeeper :: (HasFieldOfType storage fieldsPartName fields, StoreHasField fields fname ftype) => Label fieldsPartName -> StoreFieldOps storage fname ftype
+ Lorentz: storeFieldOpsReferTo :: Label name -> StoreFieldOps storage name field -> StoreFieldOps storage desiredName field
+ Lorentz: storeSubmapOps :: StoreHasSubmap store mname key value => StoreSubmapOps store mname key value
+ Lorentz: storeSubmapOpsDeeper :: (HasFieldOfType storage bigMapPartName fields, StoreHasSubmap fields mname key value) => Label bigMapPartName -> StoreSubmapOps storage mname key value
+ Lorentz: storeSubmapOpsReferTo :: Label name -> StoreSubmapOps storage name key value -> StoreSubmapOps storage desiredName key value
+ Lorentz: sub :: ArithOpHs Sub n m => (n & (m & s)) :-> (ArithResHs Sub n m & s)
+ Lorentz: subDocToMarkdown :: HeaderLevel -> SubDoc -> Markdown
+ Lorentz: swap :: (a & (b & s)) :-> (b & (a & s))
+ Lorentz: testAssert :: (Typeable (ToTs out), HasCallStack) => Text -> PrintComment (ToTs inp) -> (inp :-> (Bool & out)) -> inp :-> inp
+ Lorentz: timestampFromSeconds :: Integer -> Timestamp
+ Lorentz: timestampFromUTCTime :: UTCTime -> Timestamp
+ Lorentz: timestampQuote :: QuasiQuoter
+ Lorentz: toAddress :: ToAddress a => a -> Address
+ Lorentz: toCVal :: IsoCValue a => a -> CValue (ToCT a)
+ Lorentz: toContractRef :: (ToContractRef cp contract, HasCallStack) => contract -> ContractRef cp
+ Lorentz: toField :: forall dt name st. InstrGetFieldC dt name => Label name -> (dt & st) :-> (GetFieldType dt name & st)
+ Lorentz: toFieldNamed :: forall dt name st. InstrGetFieldC dt name => Label name -> (dt & st) :-> ((name :! GetFieldType dt name) & st)
+ Lorentz: toMutez :: Word32 -> Mutez
+ Lorentz: toNamed :: Label name -> (a : s) :-> (NamedF Identity a name : s)
+ Lorentz: toVal :: (IsoValue a, Generic a, GIsoValue (Rep a), ToT a ~ GValueType (Rep a)) => a -> Value (ToT a)
+ Lorentz: transferTokens :: forall p s. NiceParameter p => (p & (Mutez & (ContractRef p & s))) :-> (Operation & s)
+ Lorentz: transformBytesLorentz :: Bool -> (ByteString -> ByteString) -> (inp :-> out) -> inp :-> out
+ Lorentz: transformStringsLorentz :: Bool -> (MText -> MText) -> (inp :-> out) -> inp :-> out
+ Lorentz: type (n :: Symbol) ?: (a :: k) = '(n, a)
+ Lorentz: type CaseTC dt out inp clauses = (InstrCaseC dt inp out, RMap (CaseClauses dt), RecFromTuple clauses, clauses ~ Rec (CaseClauseL inp out) (CaseClauses dt))
+ Lorentz: type Coercible_ a b = ToT a ~ ToT b
+ Lorentz: type ConstraintDIPNLorentz (n :: Peano) (inp :: [Type]) (out :: [Type]) (s :: [Type]) (s' :: [Type]) = (ConstraintDIPN n (ToTs inp) (ToTs out) (ToTs s) (ToTs s'), ConstraintDIPN' Type n inp out s s')
+ Lorentz: type ConstructorFieldTypes dt = GFieldTypes (Rep dt)
+ Lorentz: type Contract cp st = '[(cp, st)] :-> ContractOut st
+ Lorentz: type ContractOut st = '[([Operation], st)]
+ Lorentz: type DocGrouping = SubDoc -> SomeDocItem
+ Lorentz: type DocItemPlacement d = 'DocItemInlined;
+ Lorentz: type EntryPointCall param arg = EntryPointCallT (ToT param) (ToT arg)
+ Lorentz: type EntryPointKind = (Symbol, Type)
+ Lorentz: type EntryPointsImpl inp out entries = Rec (CaseClauseU inp out) entries
+ Lorentz: type Entrypoint param store = '[param, store] :-> ContractOut store
+ Lorentz: type Entrypoint_ store = '[store] :-> ContractOut store
+ Lorentz: type ErrorTagMap = Bimap Natural MText
+ Lorentz: type GetUStoreField store name = FSValue (GetUStore name store)
+ Lorentz: type GetUStoreFieldMarker store name = FSMarker (GetUStore name store)
+ Lorentz: type GetUStoreKey store name = MSKey (GetUStore name store)
+ Lorentz: type GetUStoreValue store name = MSValue (GetUStore name store)
+ Lorentz: type HasField dt fname = (InstrGetFieldC dt fname, InstrSetFieldC dt fname)
+ Lorentz: type HasFieldOfType dt fname fieldTy = (HasField dt fname, GetFieldType dt fname ~ fieldTy)
+ Lorentz: type HasUField name ty store = (FieldAccessC store name, GetUStoreField store name ~ ty)
+ Lorentz: type HasUStore name key value store = (KeyAccessC store name, ValueAccessC store name, GetUStoreKey store name ~ key, GetUStoreValue store name ~ value)
+ Lorentz: type HasUStoreForAllIn store constrained = (Generic store, GHasStoreForAllIn constrained (Rep store))
+ Lorentz: type IfCmpXConstraints a op = (Typeable a, ArithOpHs Compare a a, UnaryArithOpHs op (ArithResHs Compare a a), UnaryArithResHs op (ArithResHs Compare a a) ~ Bool)
+ Lorentz: type InitUStore = UStore ()
+ Lorentz: type InstrConstructC dt = (IsoValue dt, Generic dt, GInstrConstruct (Rep dt), GValueType (Rep dt) ~ ToT dt)
+ Lorentz: type FailUsingArg e name fieldTy s s' = (KnownSymbol name, IsError e, IsoValue fieldTy, CtorHasOnlyField name e fieldTy, Each [Typeable, SingI] '[ToT fieldTy], HasCallStack) => Label name -> fieldTy : s :-> s'
+ Lorentz: type Lambda i o = '[i] :-> '[o]
+ Lorentz: type List = []
+ Lorentz: type Markdown = Builder
+ Lorentz: type NiceConstant a = (KnownValue a, ProperConstantBetterErrors (ToT a))
+ Lorentz: type NiceFullPackedValue a = (NicePackedValue a, NiceUnpackedValue a)
+ Lorentz: type NicePackedValue a = (KnownValue a, ProperPackedValBetterErrors (ToT a))
+ Lorentz: type NiceParameter a = (KnownValue a, ProperParameterBetterErrors (ToT a))
+ Lorentz: type NicePrintedValue a = (KnownValue a, ProperPrintedValBetterErrors (ToT a))
+ Lorentz: type NiceStorage a = (KnownValue a, ProperStorageBetterErrors (ToT a))
+ Lorentz: type NiceUnpackedValue a = (KnownValue a, ProperUnpackedValBetterErrors (ToT a))
+ Lorentz: type Operation = Operation' Instr
+ Lorentz: type PickMarkedFields marker template = GPickMarkedFields marker (Rep template)
+ Lorentz: type ShowUStoreField marker v = 'Text "field of type " :<>: 'ShowType v;
+ Lorentz: type SomeEntryPointCall arg = SomeEntryPointCallT (ToT arg)
+ Lorentz: type ToT a = GValueType (Rep a);
+ Lorentz: type UParamFallback inp out = ((MText, ByteString) : inp) :-> out
+ Lorentz: type UParamLinearize p = (Generic p, GUParamLinearize (Rep p))
+ Lorentz: type UParamLinearized p = GUParamLinearized (Rep p)
+ Lorentz: type UStoreField = UStoreFieldExt UMarkerPlainField
+ Lorentz: type UStoreMarkerType = UStoreMarker -> Type
+ Lorentz: type UStoreMigrationT ot nt = UStoreMigration (UStore ot) (UStore nt)
+ Lorentz: type Value = Value' Instr
+ Lorentz: type family StorageContains store (content :: [NamedField]) :: Constraint
+ Lorentz: type n := ty = 'NamedField n ty
+ Lorentz: typeDocDependencies :: (TypeHasDoc a, Generic a, GTypeHasDoc (Rep a)) => Proxy a -> [SomeTypeWithDoc]
+ Lorentz: typeDocHaskellRep :: (TypeHasDoc a, Generic a, GTypeHasDoc (Rep a), IsHomomorphic a) => TypeDocHaskellRep a
+ Lorentz: typeDocMdDescription :: TypeHasDoc a => Markdown
+ Lorentz: typeDocMdDescriptionReferToError :: forall e. IsError e => Markdown
+ Lorentz: typeDocMdReference :: (TypeHasDoc a, Typeable a, IsHomomorphic a) => Proxy a -> WithinParens -> Markdown
+ Lorentz: typeDocMichelsonRep :: (TypeHasDoc a, SingI (ToT a), IsHomomorphic a) => TypeDocMichelsonRep a
+ Lorentz: typeDocName :: (TypeHasDoc a, Generic a, KnownSymbol (GenericTypeName a)) => Proxy a -> Text
+ Lorentz: unFutureContract :: (FutureContract p : s) :-> (Address : s)
+ Lorentz: undefined :: HasCallStack => a
+ Lorentz: unit :: s :-> (() & s)
+ Lorentz: unliftUStore :: Generic template => Label name -> (UStore template : s) :-> (UStore (GetFieldType template name) : s)
+ Lorentz: unpack :: forall a s. NiceUnpackedValue a => (ByteString & s) :-> (Maybe a & s)
+ Lorentz: unpackUParam :: UnpackUParam c entries => UParam entries -> Either EntryPointLookupError (MText, ConstrainedSome c)
+ Lorentz: unpair :: ((a, b) & s) :-> (a & (b & s))
+ Lorentz: unwrapUParam :: (UParam entries : s) :-> ((MText, ByteString) : s)
+ Lorentz: unwrapUnsafe_ :: forall dt name st. InstrUnwrapC dt name => Label name -> (dt & st) :-> (CtorOnlyField name dt : st)
+ Lorentz: uparamFallbackFail :: UParamFallback inp out
+ Lorentz: uparamFromAdt :: UParamLinearize up => up -> UParam (UParamLinearized up)
+ Lorentz: update :: UpdOpHs c => (UpdOpKeyHs c & (UpdOpParamsHs c & (c & s))) :-> (c & s)
+ Lorentz: 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)
+ Lorentz: useNumericErrors :: HasCallStack => (inp :-> out) -> (inp :-> out, ErrorTagMap)
+ Lorentz: ustoreDecompose :: forall template. UStoreConversible template => UStore template -> Either Text (UStoreContent, template)
+ Lorentz: ustoreDecomposeFull :: forall template. UStoreConversible template => UStore template -> Either Text template
+ Lorentz: ustoreDelete :: forall store name s. KeyAccessC store name => Label name -> (GetUStoreKey store name : (UStore store : s)) :-> (UStore store : s)
+ Lorentz: ustoreGet :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (GetUStoreKey store name : (UStore store : s)) :-> (Maybe (GetUStoreValue store name) : s)
+ Lorentz: ustoreGetField :: forall store name s. FieldAccessC store name => Label name -> (UStore store : s) :-> (GetUStoreField store name : (UStore store : s))
+ Lorentz: ustoreInsert :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (GetUStoreKey store name : (GetUStoreValue store name : (UStore store : s))) :-> (UStore store : s)
+ Lorentz: ustoreInsertNew :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (forall s0 any. (GetUStoreKey store name : s0) :-> any) -> (GetUStoreKey store name : (GetUStoreValue store name : (UStore store : s))) :-> (UStore store : s)
+ Lorentz: ustoreMem :: forall store name s. KeyAccessC store name => Label name -> (GetUStoreKey store name : (UStore store : s)) :-> (Bool : s)
+ Lorentz: ustoreSetField :: forall store name s. FieldAccessC store name => Label name -> (GetUStoreField store name : (UStore store : s)) :-> (UStore store : s)
+ Lorentz: ustoreToField :: forall store name s. FieldAccessC store name => Label name -> (UStore store : s) :-> (GetUStoreField store name : s)
+ Lorentz: ustoreUpdate :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (GetUStoreKey store name : (Maybe (GetUStoreValue store name) : (UStore store : s))) :-> (UStore store : s)
+ Lorentz: view_ :: NiceParameter r => (forall s0. ((a, storage) & s0) :-> (r : s0)) -> (View a r & (storage & s)) :-> ((List Operation, storage) & s)
+ Lorentz: void_ :: forall a b s s' anything. (IsError (VoidResult b), KnownValue b) => ((a & s) :-> (b & s')) -> (Void_ a b & s) :-> anything
+ Lorentz: withDict :: HasDict c e => e -> (c -> r) -> r
+ Lorentz: wrap_ :: forall dt name st. InstrWrapC dt name => Label name -> AppendCtorField (GetCtorField dt name) st :-> (dt & st)
+ Lorentz: xor :: ArithOpHs Xor n m => (n & (m & s)) :-> (ArithResHs Xor n m & s)
+ Lorentz: }
+ Lorentz.ADT: [CaseClauseL] :: (AppendCtorField x inp :-> out) -> CaseClauseL inp out ( 'CaseClauseParam ctor x)
+ Lorentz.ADT: argDef :: () => Name name -> a -> (name :? a) -> a
+ Lorentz.ADT: argF :: () => Name name -> NamedF f a name -> f a
+ Lorentz.ADT: class CaseArrow name body clause | clause -> name, clause -> body
+ Lorentz.ADT: data CaseClauseL (inp :: [Type]) (out :: [Type]) (param :: CaseClauseParam)
+ Lorentz.ADT: instance (name Data.Type.Equality.~ GHC.TypeLits.AppendSymbol "c" ctor, body Data.Type.Equality.~ (Michelson.Typed.Haskell.Instr.Sum.AppendCtorField x inp Lorentz.Base.:-> out)) => Lorentz.ADT.CaseArrow name body (Lorentz.ADT.CaseClauseL inp out ('Michelson.Typed.Haskell.Instr.Sum.CaseClauseParam ctor x))
+ Lorentz.ADT: type CaseTC dt out inp clauses = (InstrCaseC dt inp out, RMap (CaseClauses dt), RecFromTuple clauses, clauses ~ Rec (CaseClauseL inp out) (CaseClauses dt))
+ Lorentz.ADT: unwrapUnsafe_ :: forall dt name st. InstrUnwrapC dt name => Label name -> (dt & st) :-> (CtorOnlyField name dt : st)
+ Lorentz.Arith: class (Typeable (ToCT n), IsComparable n, CompareOp (ToCT n)) => CompareOpHs n
+ Lorentz.Arith: instance (n Data.Type.Equality.~ m, Lorentz.Arith.CompareOpHs n) => Lorentz.Arith.ArithOpHs Michelson.Typed.Arith.Compare n m
+ Lorentz.Arith: instance Lorentz.Arith.CompareOpHs Data.ByteString.Internal.ByteString
+ Lorentz.Arith: instance Lorentz.Arith.CompareOpHs GHC.Integer.Type.Integer
+ Lorentz.Arith: instance Lorentz.Arith.CompareOpHs GHC.Natural.Natural
+ Lorentz.Arith: instance Lorentz.Arith.CompareOpHs GHC.Types.Bool
+ Lorentz.Arith: instance Lorentz.Arith.CompareOpHs Michelson.Text.MText
+ Lorentz.Arith: instance Lorentz.Arith.CompareOpHs Michelson.Typed.EntryPoints.EpAddress
+ Lorentz.Arith: instance Lorentz.Arith.CompareOpHs Tezos.Address.Address
+ Lorentz.Arith: instance Lorentz.Arith.CompareOpHs Tezos.Core.Mutez
+ Lorentz.Arith: instance Lorentz.Arith.CompareOpHs Tezos.Core.Timestamp
+ Lorentz.Arith: instance Lorentz.Arith.CompareOpHs Tezos.Crypto.KeyHash
+ Lorentz.Base: LorentzInstr :: RemFail Instr (ToTs inp) (ToTs out) -> (:->)
+ Lorentz.Base: [SomeContract] :: (NiceParameter cp, NiceStorage st) => Contract cp st -> SomeContract
+ Lorentz.Base: [unLorentzInstr] :: (:->) -> RemFail Instr (ToTs inp) (ToTs out)
+ Lorentz.Base: data SomeContract
+ Lorentz.Base: iAnyCode :: (inp :-> out) -> Instr (ToTs inp) (ToTs out)
+ Lorentz.Base: iGenericIf :: (forall s'. Instr (ToTs a) s' -> Instr (ToTs b) s' -> Instr (ToTs c) s') -> (a :-> s) -> (b :-> s) -> c :-> s
+ Lorentz.Base: iMapAnyCode :: (forall o'. Instr (ToTs i1) o' -> Instr (ToTs i2) o') -> (i1 :-> o) -> i2 :-> o
+ Lorentz.Base: iNonFailingCode :: HasCallStack => (inp :-> out) -> Instr (ToTs inp) (ToTs out)
+ Lorentz.Base: infixl 8 #
+ Lorentz.Base: instance Formatting.Buildable.Buildable Lorentz.Base.ParseLorentzError
+ Lorentz.Base: instance GHC.Base.Monoid (s Lorentz.Base.:-> s)
+ Lorentz.Base: instance GHC.Base.Semigroup (s Lorentz.Base.:-> s)
+ Lorentz.Base: instance GHC.Classes.Eq Lorentz.Base.ParseLorentzError
+ Lorentz.Base: instance GHC.Show.Show Lorentz.Base.ParseLorentzError
+ Lorentz.Base: optimizeLorentz :: (inp :-> out) -> inp :-> out
+ Lorentz.Base: optimizeLorentzWithConf :: OptimizerConf -> (inp :-> out) -> inp :-> out
+ Lorentz.Base: parseLorentzValue :: forall v. (IsoValue v, SingI (ToT v), Typeable (ToT v)) => Text -> Either ParseLorentzError v
+ Lorentz.Base: pattern FI :: (forall out'. Instr (ToTs inp) out') -> inp :-> out
+ Lorentz.Base: pattern I :: Instr (ToTs inp) (ToTs out) -> inp :-> out
+ Lorentz.Base: transformBytesLorentz :: Bool -> (ByteString -> ByteString) -> (inp :-> out) -> inp :-> out
+ Lorentz.Base: transformStringsLorentz :: Bool -> (MText -> MText) -> (inp :-> out) -> inp :-> out
+ Lorentz.Coercions: fakeCoerce :: s1 :-> s2
+ Lorentz.Coercions: futureContract :: (Address : s) :-> (FutureContract p : s)
+ Lorentz.Coercions: gcoerce_ :: Coercible_ (t a) (t b) => (t a : s) :-> (t b : s)
+ Lorentz.Coercions: unFutureContract :: (FutureContract p : s) :-> (Address : s)
+ Lorentz.Common: type Entrypoint param store = '[param, store] :-> ContractOut store
+ Lorentz.Common: type Entrypoint_ store = '[store] :-> ContractOut store
+ Lorentz.Constraints: class (IsoValue a, HasNoNestedBigMaps (ToT a)) => CanHaveBigMap a
+ Lorentz.Constraints: class (IsoValue a, Typeable (ToCT a), SingI (ToCT a)) => KnownCValue a
+ Lorentz.Constraints: class (IsoValue a, Typeable (ToT a), SingI (ToT a)) => KnownValue a
+ Lorentz.Constraints: class (IsoValue a, ForbidBigMap (ToT a)) => NoBigMap a
+ Lorentz.Constraints: class (IsoValue a, ForbidContract (ToT a)) => NoContractType a
+ Lorentz.Constraints: class (IsoValue a, ForbidOp (ToT a)) => NoOperation a
+ Lorentz.Constraints: instance (Michelson.Typed.Haskell.Value.IsoValue a, Data.Typeable.Internal.Typeable (Michelson.Typed.Haskell.Value.ToCT a), Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.ToCT a)) => Lorentz.Constraints.KnownCValue a
+ Lorentz.Constraints: instance (Michelson.Typed.Haskell.Value.IsoValue a, Data.Typeable.Internal.Typeable (Michelson.Typed.Haskell.Value.ToT a), Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.ToT a)) => Lorentz.Constraints.KnownValue a
+ Lorentz.Constraints: instance (Michelson.Typed.Haskell.Value.IsoValue a, Michelson.Typed.Scope.ForbidBigMap (Michelson.Typed.Haskell.Value.ToT a)) => Lorentz.Constraints.NoBigMap a
+ Lorentz.Constraints: instance (Michelson.Typed.Haskell.Value.IsoValue a, Michelson.Typed.Scope.ForbidContract (Michelson.Typed.Haskell.Value.ToT a)) => Lorentz.Constraints.NoContractType a
+ Lorentz.Constraints: instance (Michelson.Typed.Haskell.Value.IsoValue a, Michelson.Typed.Scope.ForbidOp (Michelson.Typed.Haskell.Value.ToT a)) => Lorentz.Constraints.NoOperation a
+ Lorentz.Constraints: instance (Michelson.Typed.Haskell.Value.IsoValue a, Michelson.Typed.Scope.HasNoNestedBigMaps (Michelson.Typed.Haskell.Value.ToT a)) => Lorentz.Constraints.CanHaveBigMap a
+ Lorentz.Constraints: niceConstantEvi :: forall a. NiceConstant a :- ConstantScope (ToT a)
+ Lorentz.Constraints: nicePackedValueEvi :: forall a. NicePackedValue a :- PackedValScope (ToT a)
+ Lorentz.Constraints: niceParameterEvi :: forall a. NiceParameter a :- ParameterScope (ToT a)
+ Lorentz.Constraints: nicePrintedValueEvi :: forall a. NicePrintedValue a :- PrintedValScope (ToT a)
+ Lorentz.Constraints: niceStorageEvi :: forall a. NiceStorage a :- StorageScope (ToT a)
+ Lorentz.Constraints: niceUnpackedValueEvi :: forall a. NiceUnpackedValue a :- UnpackedValScope (ToT a)
+ Lorentz.Constraints: type NiceConstant a = (KnownValue a, ProperConstantBetterErrors (ToT a))
+ Lorentz.Constraints: type NiceFullPackedValue a = (NicePackedValue a, NiceUnpackedValue a)
+ Lorentz.Constraints: type NicePackedValue a = (KnownValue a, ProperPackedValBetterErrors (ToT a))
+ Lorentz.Constraints: type NiceParameter a = (KnownValue a, ProperParameterBetterErrors (ToT a))
+ Lorentz.Constraints: type NicePrintedValue a = (KnownValue a, ProperPrintedValBetterErrors (ToT a))
+ Lorentz.Constraints: type NiceStorage a = (KnownValue a, ProperStorageBetterErrors (ToT a))
+ Lorentz.Constraints: type NiceUnpackedValue a = (KnownValue a, ProperUnpackedValBetterErrors (ToT a))
+ Lorentz.Constraints: withDict :: HasDict c e => e -> (c -> r) -> r
+ Lorentz.Doc: --
+ Lorentz.Doc: -- Documentation structure is not necessarily flat. If some doc item
+ Lorentz.Doc: -- Inline right here (default behaviour); 2. Put into definitions
+ Lorentz.Doc: -- Note that we require all doc items with "in definitions" placement to
+ Lorentz.Doc: -- consolidates a whole documentation block within it, this block will
+ Lorentz.Doc: -- doc.
+ Lorentz.Doc: -- have <a>Eq</a> and <a>Ord</a> instances which comply the following
+ Lorentz.Doc: -- law: if two documentation items describe the same entity or property,
+ Lorentz.Doc: -- section.
+ Lorentz.Doc: -- they should be considered equal.
+ Lorentz.Doc: -- value, the higher the section with this element will be placed.
+ Lorentz.Doc: -- | Defines where given doc item should be put. There are two options: 1.
+ Lorentz.Doc: ContractDoc :: DocBlock -> DocBlock -> Set SomeDocDefinitionItem -> Set DocItemId -> ContractDoc
+ Lorentz.Doc: DComment :: Text -> DComment
+ Lorentz.Doc: DDescription :: Markdown -> DDescription
+ Lorentz.Doc: DGitRevision :: GitRepoSettings -> Text -> Text -> DGitRevision
+ Lorentz.Doc: DVersion :: Natural -> DVersion
+ Lorentz.Doc: DocItemId :: Text -> DocItemId
+ Lorentz.Doc: DocItemInDefinitions :: DocItemPlacementKind
+ Lorentz.Doc: DocItemInlined :: DocItemPlacementKind
+ Lorentz.Doc: DocSectionNameBig :: DocSectionNameStyle
+ Lorentz.Doc: DocSectionNameSmall :: DocSectionNameStyle
+ Lorentz.Doc: GitRepoSettings :: (Text -> Text) -> GitRepoSettings
+ Lorentz.Doc: SubDoc :: DocBlock -> SubDoc
+ Lorentz.Doc: [DType] :: TypeHasDoc a => Proxy a -> DType
+ Lorentz.Doc: [DocItemNoRef] :: DocItemRef 'DocItemInlined
+ Lorentz.Doc: [DocItemRef] :: DocItemId -> DocItemRef 'DocItemInDefinitions
+ Lorentz.Doc: [SomeDocDefinitionItem] :: (DocItem d, DocItemPlacement d ~ 'DocItemInDefinitions) => d -> SomeDocDefinitionItem
+ Lorentz.Doc: [SomeDocItem] :: DocItem d => d -> SomeDocItem
+ Lorentz.Doc: [SomeTypeWithDoc] :: TypeHasDoc td => Proxy td -> SomeTypeWithDoc
+ Lorentz.Doc: [cdContents] :: ContractDoc -> DocBlock
+ Lorentz.Doc: [cdDefinitionIds] :: ContractDoc -> Set DocItemId
+ Lorentz.Doc: [cdDefinitionsSet] :: ContractDoc -> Set SomeDocDefinitionItem
+ Lorentz.Doc: [cdDefinitions] :: ContractDoc -> DocBlock
+ Lorentz.Doc: [dgrCommitDate] :: DGitRevision -> Text
+ Lorentz.Doc: [dgrCommitSha] :: DGitRevision -> Text
+ Lorentz.Doc: [dgrRepoSettings] :: DGitRevision -> GitRepoSettings
+ Lorentz.Doc: [grsMkGitRevision] :: GitRepoSettings -> Text -> Text
+ Lorentz.Doc: buildLorentzDoc :: (inp :-> out) -> ContractDoc
+ Lorentz.Doc: class (Typeable d, DOrd d, KnownNat (DocItemPosition d)) => DocItem d where {
+ Lorentz.Doc: class HaveCommonTypeCtor a b
+ Lorentz.Doc: class IsHomomorphic a
+ Lorentz.Doc: class Typeable a => TypeHasDoc a
+ Lorentz.Doc: concreteTypeDocHaskellRep :: forall a b. (Typeable a, IsoValue a, Generic a, GTypeHasDoc (Rep a), HaveCommonTypeCtor b a) => TypeDocHaskellRep b
+ Lorentz.Doc: concreteTypeDocHaskellRepUnsafe :: forall a b. (Typeable a, IsoValue a, Generic a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep b
+ Lorentz.Doc: concreteTypeDocMichelsonRep :: forall a b. (Typeable a, SingI (ToT a), HaveCommonTypeCtor b a) => TypeDocMichelsonRep b
+ Lorentz.Doc: concreteTypeDocMichelsonRepUnsafe :: forall a b. (Typeable a, SingI (ToT a)) => TypeDocMichelsonRep b
+ Lorentz.Doc: contractDocToMarkdown :: ContractDoc -> LText
+ Lorentz.Doc: contractName :: Text -> (inp :-> out) -> inp :-> out
+ Lorentz.Doc: customTypeDocMdReference :: (Text, DType) -> [DType] -> WithinParens -> Markdown
+ Lorentz.Doc: cutLorentzNonDoc :: (inp :-> out) -> s :-> s
+ Lorentz.Doc: data ContractDoc
+ Lorentz.Doc: data DComment
+ Lorentz.Doc: data DDescription
+ Lorentz.Doc: data DGitRevision
+ Lorentz.Doc: data DType
+ Lorentz.Doc: data DVersion
+ Lorentz.Doc: data DocItemPlacementKind
+ Lorentz.Doc: data DocItemRef (p :: DocItemPlacementKind)
+ Lorentz.Doc: data DocSectionNameStyle
+ Lorentz.Doc: data SomeDocDefinitionItem
+ Lorentz.Doc: data SomeDocItem
+ Lorentz.Doc: data SomeTypeWithDoc
+ Lorentz.Doc: doc :: DocItem di => di -> s :-> s
+ Lorentz.Doc: docDefinitionRef :: (DocItem d, DocItemPlacement d ~ 'DocItemInDefinitions) => Markdown -> d -> Markdown
+ Lorentz.Doc: docGroup :: DocGrouping -> (inp :-> out) -> inp :-> out
+ Lorentz.Doc: docItemDependencies :: DocItem d => d -> [SomeDocDefinitionItem]
+ Lorentz.Doc: docItemPosition :: forall d. DocItem d => DocItemPos
+ Lorentz.Doc: docItemRef :: (DocItem d, DocItemPlacement d ~ 'DocItemInlined) => d -> DocItemRef (DocItemPlacement d)
+ Lorentz.Doc: docItemSectionDescription :: DocItem d => Maybe Markdown
+ Lorentz.Doc: docItemSectionName :: DocItem d => Maybe Text
+ Lorentz.Doc: docItemSectionNameStyle :: DocItem d => DocSectionNameStyle
+ Lorentz.Doc: docItemToMarkdown :: DocItem d => HeaderLevel -> d -> Markdown
+ Lorentz.Doc: docItemsOrder :: DocItem d => [d] -> [d]
+ Lorentz.Doc: genericTypeDocDependencies :: forall a. (Generic a, GTypeHasDoc (Rep a)) => Proxy a -> [SomeTypeWithDoc]
+ Lorentz.Doc: haskellRepNoFields :: TypeDocHaskellRep a -> TypeDocHaskellRep a
+ Lorentz.Doc: haskellRepStripFieldPrefix :: HasCallStack => TypeDocHaskellRep a -> TypeDocHaskellRep a
+ Lorentz.Doc: homomorphicTypeDocHaskellRep :: forall a. (Generic a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep a
+ Lorentz.Doc: homomorphicTypeDocMdReference :: forall (t :: Type). (Typeable t, TypeHasDoc t, IsHomomorphic t) => Proxy t -> WithinParens -> Markdown
+ Lorentz.Doc: homomorphicTypeDocMichelsonRep :: forall a. SingI (ToT a) => TypeDocMichelsonRep a
+ Lorentz.Doc: instance Universum.TypeOps.Each '[Data.Typeable.Internal.Typeable, Util.Type.ReifyList Michelson.Typed.Haskell.Doc.TypeHasDoc] '[i, o] => Michelson.Typed.Haskell.Doc.TypeHasDoc (i Lorentz.Base.:-> o)
+ Lorentz.Doc: mkDGitRevision :: Q Exp
+ Lorentz.Doc: morleyRepoSettings :: GitRepoSettings
+ Lorentz.Doc: newtype DocItemId
+ Lorentz.Doc: newtype GitRepoSettings
+ Lorentz.Doc: newtype SubDoc
+ Lorentz.Doc: poly1TypeDocMdReference :: forall t (r :: Type) (a :: Type). (r ~ t a, Typeable t, Each '[TypeHasDoc] [r, a], IsHomomorphic t) => Proxy r -> WithinParens -> Markdown
+ Lorentz.Doc: poly2TypeDocMdReference :: forall t (r :: Type) (a :: Type) (b :: Type). (r ~ t a b, Typeable t, Each '[TypeHasDoc] [r, a, b], IsHomomorphic t) => Proxy r -> WithinParens -> Markdown
+ Lorentz.Doc: renderLorentzDoc :: (inp :-> out) -> LText
+ Lorentz.Doc: subDocToMarkdown :: HeaderLevel -> SubDoc -> Markdown
+ Lorentz.Doc: type DocGrouping = SubDoc -> SomeDocItem
+ Lorentz.Doc: type DocItemPlacement d = 'DocItemInlined;
+ Lorentz.Doc: type Markdown = Builder
+ Lorentz.Doc: type family DocItemPlacement d :: DocItemPlacementKind;
+ Lorentz.Doc: typeDocDependencies :: (TypeHasDoc a, Generic a, GTypeHasDoc (Rep a)) => Proxy a -> [SomeTypeWithDoc]
+ Lorentz.Doc: typeDocHaskellRep :: (TypeHasDoc a, Generic a, GTypeHasDoc (Rep a), IsHomomorphic a) => TypeDocHaskellRep a
+ Lorentz.Doc: typeDocMdDescription :: TypeHasDoc a => Markdown
+ Lorentz.Doc: typeDocMdReference :: (TypeHasDoc a, Typeable a, IsHomomorphic a) => Proxy a -> WithinParens -> Markdown
+ Lorentz.Doc: typeDocMichelsonRep :: (TypeHasDoc a, SingI (ToT a), IsHomomorphic a) => TypeDocMichelsonRep a
+ Lorentz.Doc: typeDocName :: (TypeHasDoc a, Generic a, KnownSymbol (GenericTypeName a)) => Proxy a -> Text
+ Lorentz.Doc: }
+ Lorentz.EntryPoints: ParameterEntryPointsSplit :: Notes (ToT p) -> ParameterEntryPointsSplit p
+ Lorentz.EntryPoints: [pesNotes] :: ParameterEntryPointsSplit p -> Notes (ToT p)
+ Lorentz.EntryPoints: class NiceParameter p => ParameterEntryPoints p
+ Lorentz.EntryPoints: instance (Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.ToCT v), Data.Typeable.Internal.Typeable (Michelson.Typed.Haskell.Value.ToCT v)) => Lorentz.EntryPoints.HasTypeAnn (Data.Set.Internal.Set v)
+ Lorentz.EntryPoints: instance (Data.Typeable.Internal.Typeable (Michelson.Typed.Haskell.Value.GValueType x), Data.Typeable.Internal.Typeable (Michelson.Typed.Haskell.Value.GValueType y), Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.GValueType x), Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.GValueType y)) => Lorentz.EntryPoints.GEntryPointsNotes deep 'Lorentz.EntryPoints.EPLeaf (x GHC.Generics.:*: y)
+ Lorentz.EntryPoints: instance (Lorentz.EntryPoints.EntryPointsNotes deep ep a, Michelson.Typed.Haskell.Value.IsGenericIsoValue a) => Lorentz.EntryPoints.GEntryPointsNotes deep ep (GHC.Generics.Rec0 a)
+ Lorentz.EntryPoints: instance (Lorentz.EntryPoints.GEntryPointsNotes deep epx x, Lorentz.EntryPoints.GEntryPointsNotes deep epy y) => Lorentz.EntryPoints.GEntryPointsNotes deep ('Lorentz.EntryPoints.EPNode epx epy) (x GHC.Generics.:+: y)
+ Lorentz.EntryPoints: instance (Lorentz.EntryPoints.GHasTypeAnn (GHC.Generics.Rep a), Michelson.Typed.Haskell.Value.GValueType (GHC.Generics.Rep a) Data.Type.Equality.~ Michelson.Typed.Haskell.Value.ToT a) => Lorentz.EntryPoints.HasTypeAnn a
+ Lorentz.EntryPoints: instance (Lorentz.EntryPoints.GHasTypeAnn x, GHC.TypeLits.KnownSymbol ctor) => Lorentz.EntryPoints.GEntryPointsNotes 'GHC.Types.False ep (GHC.Generics.C1 ('GHC.Generics.MetaCons ctor _1 _2) x)
+ Lorentz.EntryPoints: instance (Lorentz.EntryPoints.GHasTypeAnn x, GHC.TypeLits.KnownSymbol ctor) => Lorentz.EntryPoints.GEntryPointsNotes 'GHC.Types.True 'Lorentz.EntryPoints.EPLeaf (GHC.Generics.C1 ('GHC.Generics.MetaCons ctor _1 _2) x)
+ Lorentz.EntryPoints: instance (Lorentz.EntryPoints.GHasTypeAnn x, Lorentz.EntryPoints.GHasTypeAnn y) => Lorentz.EntryPoints.GHasTypeAnn (x GHC.Generics.:*: y)
+ Lorentz.EntryPoints: instance (Lorentz.EntryPoints.GHasTypeAnn x, Lorentz.EntryPoints.GHasTypeAnn y) => Lorentz.EntryPoints.GHasTypeAnn (x GHC.Generics.:+: y)
+ Lorentz.EntryPoints: instance (Lorentz.EntryPoints.HasTypeAnn (GHC.Maybe.Maybe a), GHC.TypeLits.KnownSymbol name) => Lorentz.EntryPoints.HasTypeAnn (Named.Internal.NamedF GHC.Maybe.Maybe a name)
+ Lorentz.EntryPoints: instance (Lorentz.EntryPoints.HasTypeAnn (Lorentz.Zip.ZippedStack i), Lorentz.EntryPoints.HasTypeAnn (Lorentz.Zip.ZippedStack o)) => Lorentz.EntryPoints.HasTypeAnn (i Lorentz.Base.:-> o)
+ Lorentz.EntryPoints: instance (Lorentz.EntryPoints.HasTypeAnn a, GHC.TypeLits.KnownSymbol name) => Lorentz.EntryPoints.HasTypeAnn (Named.Internal.NamedF Data.Functor.Identity.Identity a name)
+ Lorentz.EntryPoints: instance (ep Data.Type.Equality.~ 'Lorentz.EntryPoints.EPNode epx epy, Lorentz.EntryPoints.GEntryPointsNotes 'GHC.Types.True ep x) => Lorentz.EntryPoints.GEntryPointsNotes 'GHC.Types.True ('Lorentz.EntryPoints.EPNode epx epy) (GHC.Generics.C1 ('GHC.Generics.MetaCons ctor _1 _2) x)
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.GEntryPointsNotes deep 'Lorentz.EntryPoints.EPLeaf GHC.Generics.U1
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.GEntryPointsNotes deep ep x => Lorentz.EntryPoints.GEntryPointsNotes deep ep (GHC.Generics.D1 i x)
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.GEntryPointsNotes deep ep x => Lorentz.EntryPoints.GEntryPointsNotes deep ep (GHC.Generics.S1 i x)
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.GHasTypeAnn GHC.Generics.U1
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.GHasTypeAnn x => Lorentz.EntryPoints.GHasTypeAnn (GHC.Generics.M1 i0 i1 x)
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn Data.ByteString.Internal.ByteString
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn GHC.Integer.Type.Integer
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn GHC.Natural.Natural
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn GHC.Types.Bool
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn Michelson.Text.MText
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn Michelson.Typed.Aliases.Operation
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn Michelson.Typed.EntryPoints.EpAddress
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn Tezos.Address.Address
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn Tezos.Core.Mutez
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn Tezos.Core.Timestamp
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn Tezos.Crypto.KeyHash
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn Tezos.Crypto.PublicKey
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn Tezos.Crypto.Signature
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn a => Lorentz.EntryPoints.HasTypeAnn (GHC.Maybe.Maybe a)
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn a => Lorentz.EntryPoints.HasTypeAnn (Michelson.Typed.Haskell.Value.ContractRef a)
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn a => Lorentz.EntryPoints.HasTypeAnn [a]
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn v => Lorentz.EntryPoints.HasTypeAnn (Data.Map.Internal.Map k v)
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn v => Lorentz.EntryPoints.HasTypeAnn (Michelson.Typed.Haskell.Value.BigMap k v)
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.HasTypeAnn x => Lorentz.EntryPoints.GHasTypeAnn (GHC.Generics.Rec0 x)
+ Lorentz.EntryPoints: instance Lorentz.EntryPoints.ParameterEntryPoints ()
+ Lorentz.EntryPoints: mapParameterEntryPoints :: ToT a ~ ToT b => (a -> b) -> ParameterEntryPointsSplit a -> ParameterEntryPointsSplit b
+ Lorentz.EntryPoints: newtype ParameterEntryPointsSplit p
+ Lorentz.EntryPoints: parameterEntryPoints :: ParameterEntryPoints p => ParameterEntryPointsSplit p
+ Lorentz.EntryPoints: pepNone :: SingI (ToT p) => ParameterEntryPointsSplit p
+ Lorentz.EntryPoints: pepPlain :: PesEntryPointsC 'False cp st => ParameterEntryPointsSplit cp
+ Lorentz.EntryPoints: pepRecursive :: PesEntryPointsC 'True cp st => ParameterEntryPointsSplit cp
+ Lorentz.EntryPoints.Doc: DEntryPoint :: Text -> SubDoc -> DEntryPoint
+ Lorentz.EntryPoints.Doc: DEntryPointArg :: Maybe DType -> [ParamBuildingStep] -> DEntryPointArg
+ Lorentz.EntryPoints.Doc: ParamBuildingStep :: Markdown -> (CurrentParam -> Markdown) -> (CurrentParam -> Markdown) -> ParamBuildingStep
+ Lorentz.EntryPoints.Doc: [epaArg] :: DEntryPointArg -> Maybe DType
+ Lorentz.EntryPoints.Doc: [epaBuilding] :: DEntryPointArg -> [ParamBuildingStep]
+ Lorentz.EntryPoints.Doc: [pbsEnglish] :: ParamBuildingStep -> Markdown
+ Lorentz.EntryPoints.Doc: [pbsHaskell] :: ParamBuildingStep -> CurrentParam -> Markdown
+ Lorentz.EntryPoints.Doc: [pbsMichelson] :: ParamBuildingStep -> CurrentParam -> Markdown
+ Lorentz.EntryPoints.Doc: clarifyParamBuildingSteps :: ParamBuildingStep -> (inp :-> out) -> inp :-> out
+ Lorentz.EntryPoints.Doc: class DeriveCtorFieldDoc (cf :: CtorField)
+ Lorentz.EntryPoints.Doc: data DEntryPoint (kind :: Type)
+ Lorentz.EntryPoints.Doc: data DEntryPointArg
+ Lorentz.EntryPoints.Doc: data ParamBuildingStep
+ Lorentz.EntryPoints.Doc: data PlainEntryPointsKind
+ Lorentz.EntryPoints.Doc: deriveCtorFieldDoc :: DeriveCtorFieldDoc cf => Maybe DType
+ Lorentz.EntryPoints.Doc: diEntryPointToMarkdown :: HeaderLevel -> DEntryPoint level -> Markdown
+ Lorentz.EntryPoints.Doc: entryCase :: forall dt entryPointKind out inp clauses. (CaseTC dt out inp clauses, DocumentEntryPoints entryPointKind dt) => Proxy entryPointKind -> IsoRecTuple clauses -> (dt & inp) :-> out
+ Lorentz.EntryPoints.Doc: instance ('Michelson.Typed.Haskell.Instr.Sum.CaseClauseParam ctor cf Data.Type.Equality.~ Michelson.Typed.Haskell.Instr.Sum.GCaseBranchInput ctor x, GHC.TypeLits.KnownSymbol ctor, Michelson.Doc.DocItem (Lorentz.EntryPoints.Doc.DEntryPoint kind), Lorentz.EntryPoints.Doc.DeriveCtorFieldDoc cf) => Lorentz.EntryPoints.Doc.GDocumentEntryPoints kind (GHC.Generics.C1 ('GHC.Generics.MetaCons ctor _1 _2) x)
+ Lorentz.EntryPoints.Doc: instance (Lorentz.EntryPoints.Doc.GDocumentEntryPoints kind x, Lorentz.EntryPoints.Doc.GDocumentEntryPoints kind y, Util.Type.RSplit (Michelson.Typed.Haskell.Instr.Sum.GCaseClauses x) (Michelson.Typed.Haskell.Instr.Sum.GCaseClauses y)) => Lorentz.EntryPoints.Doc.GDocumentEntryPoints kind (x GHC.Generics.:+: y)
+ Lorentz.EntryPoints.Doc: instance Lorentz.EntryPoints.Doc.DeriveCtorFieldDoc 'Michelson.Typed.Haskell.Instr.Sum.NoFields
+ Lorentz.EntryPoints.Doc: instance Lorentz.EntryPoints.Doc.GDocumentEntryPoints kind x => Lorentz.EntryPoints.Doc.GDocumentEntryPoints kind (GHC.Generics.D1 i x)
+ Lorentz.EntryPoints.Doc: instance Michelson.Doc.DocItem (Lorentz.EntryPoints.Doc.DEntryPoint Lorentz.EntryPoints.Doc.PlainEntryPointsKind)
+ Lorentz.EntryPoints.Doc: instance Michelson.Doc.DocItem Lorentz.EntryPoints.Doc.DEntryPointArg
+ Lorentz.EntryPoints.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc ty => Lorentz.EntryPoints.Doc.DeriveCtorFieldDoc ('Michelson.Typed.Haskell.Instr.Sum.OneField ty)
+ Lorentz.EntryPoints.Doc: mkDEntryPointArgSimple :: forall t. TypeHasDoc t => DEntryPointArg
+ Lorentz.Errors: CustomError :: Label tag -> ErrorArg tag -> CustomError
+ Lorentz.Errors: ErrClassActionException :: ErrorClass
+ Lorentz.Errors: ErrClassBadArgument :: ErrorClass
+ Lorentz.Errors: ErrClassContractInternal :: ErrorClass
+ Lorentz.Errors: ErrClassUnknown :: ErrorClass
+ Lorentz.Errors: UnspecifiedError :: UnspecifiedError
+ Lorentz.Errors: [DError] :: IsError e => Proxy e -> DError
+ Lorentz.Errors: [DThrows] :: IsError e => Proxy e -> DThrows
+ Lorentz.Errors: [ceArg] :: CustomError -> ErrorArg tag
+ Lorentz.Errors: [ceTag] :: CustomError -> Label tag
+ Lorentz.Errors: class (KnownSymbol tag, TypeHasDoc (ErrorArg tag), IsError (CustomError tag)) => CustomErrorHasDoc tag
+ Lorentz.Errors: class ErrorHasDoc e
+ Lorentz.Errors: class (Typeable e, ErrorHasDoc e) => IsError e
+ Lorentz.Errors: customErrArgumentSemantics :: CustomErrorHasDoc tag => Maybe Markdown
+ Lorentz.Errors: customErrClass :: CustomErrorHasDoc tag => ErrorClass
+ Lorentz.Errors: customErrDocMdCause :: CustomErrorHasDoc tag => Markdown
+ Lorentz.Errors: customErrDocMdCauseInEntrypoint :: CustomErrorHasDoc tag => Markdown
+ Lorentz.Errors: customErrorFromVal :: forall t e. (SingI t, LooseSumC e) => Value t -> Either Text e
+ Lorentz.Errors: customErrorToVal :: (LooseSumC e, HasCallStack) => e -> (forall t. ErrorScope t => Value t -> r) -> r
+ Lorentz.Errors: data CustomError (tag :: Symbol)
+ Lorentz.Errors: data DError
+ Lorentz.Errors: data DThrows
+ Lorentz.Errors: data ErrorClass
+ Lorentz.Errors: data UnspecifiedError
+ Lorentz.Errors: deriveCustomError :: Name -> Q [Dec]
+ Lorentz.Errors: errorDocClass :: ErrorHasDoc e => ErrorClass
+ Lorentz.Errors: errorDocDependencies :: ErrorHasDoc e => [SomeDocDefinitionItem]
+ Lorentz.Errors: errorDocHaskellRep :: ErrorHasDoc e => Markdown
+ Lorentz.Errors: errorDocMdCause :: ErrorHasDoc e => Markdown
+ Lorentz.Errors: errorDocMdCauseInEntrypoint :: ErrorHasDoc e => Markdown
+ Lorentz.Errors: errorDocName :: ErrorHasDoc e => Text
+ Lorentz.Errors: errorFromVal :: (IsError e, Typeable t, SingI t) => Value t -> Either Text e
+ Lorentz.Errors: errorToVal :: IsError e => e -> (forall t. ErrorScope t => Value t -> r) -> r
+ Lorentz.Errors: errorsDocumentation :: Markdown
+ Lorentz.Errors: failCustom :: forall tag err s any. (err ~ ErrorArg tag, CustomErrorHasDoc tag, KnownError err) => Label tag -> (err : s) :-> any
+ Lorentz.Errors: failCustom_ :: forall tag s any notVoidError. (TypeErrorUnless (ErrorArg tag == ()) notVoidError, CustomErrorHasDoc tag, notVoidError ~ ( 'Text "Expected no-arg error, but given error requires argument of type " :<>: 'ShowType (ErrorArg tag))) => Label tag -> s :-> any
+ Lorentz.Errors: failUnexpected :: MText -> s :-> t
+ Lorentz.Errors: failUsing :: forall e s t. IsError e => e -> s :-> t
+ Lorentz.Errors: failUsingArg :: forall err name fieldTy s s'. FailUsingArg err name fieldTy s s'
+ Lorentz.Errors: instance (Data.Typeable.Internal.Typeable arg, Lorentz.Errors.IsError (Lorentz.Errors.CustomError tag), Util.TypeLits.TypeErrorUnless (arg Data.Type.Equality.== ()) notVoidError, arg Data.Type.Equality.~ Lorentz.Errors.ErrorArg tag, notVoidError Data.Type.Equality.~ ('GHC.TypeLits.Text "This error requires argument of type " 'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType (Lorentz.Errors.ErrorArg tag))) => Lorentz.Errors.IsError (arg -> Lorentz.Errors.CustomError tag)
+ Lorentz.Errors: instance (Lorentz.Errors.CustomErrorHasDoc tag, Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.ToT (Lorentz.Errors.ErrorArg tag))) => Lorentz.Errors.ErrorHasDoc (Lorentz.Errors.CustomError tag)
+ Lorentz.Errors: instance (Lorentz.Errors.CustomErrorHasDoc tag, Lorentz.Errors.KnownError (Lorentz.Errors.ErrorArg tag), Michelson.Typed.Haskell.Value.IsoValue (Lorentz.Errors.ErrorArg tag)) => Lorentz.Errors.IsError (Lorentz.Errors.CustomError tag)
+ Lorentz.Errors: instance (TypeError ...) => Lorentz.Errors.ErrorHasDoc ()
+ Lorentz.Errors: instance (TypeError ...) => Lorentz.Errors.IsError ()
+ Lorentz.Errors: instance (TypeError ...) => Michelson.Typed.Haskell.Value.IsoValue (Lorentz.Errors.CustomError tag)
+ Lorentz.Errors: instance Formatting.Buildable.Buildable Lorentz.Errors.ErrorClass
+ Lorentz.Errors: instance GHC.Classes.Eq (Lorentz.Errors.ErrorArg tag) => GHC.Classes.Eq (() -> Lorentz.Errors.CustomError tag)
+ Lorentz.Errors: instance GHC.Classes.Eq (Lorentz.Errors.ErrorArg tag) => GHC.Classes.Eq (Lorentz.Errors.CustomError tag)
+ Lorentz.Errors: instance GHC.Classes.Eq Lorentz.Errors.DError
+ Lorentz.Errors: instance GHC.Classes.Eq Lorentz.Errors.DThrows
+ Lorentz.Errors: instance GHC.Classes.Ord Lorentz.Errors.DError
+ Lorentz.Errors: instance GHC.Generics.Generic Lorentz.Errors.UnspecifiedError
+ Lorentz.Errors: instance GHC.Show.Show (Lorentz.Errors.ErrorArg tag) => GHC.Show.Show (() -> Lorentz.Errors.CustomError tag)
+ Lorentz.Errors: instance GHC.Show.Show (Lorentz.Errors.ErrorArg tag) => GHC.Show.Show (Lorentz.Errors.CustomError tag)
+ Lorentz.Errors: instance Lorentz.Errors.ErrorHasDoc (Lorentz.Errors.CustomError tag) => Lorentz.Errors.ErrorHasDoc (arg -> Lorentz.Errors.CustomError tag)
+ Lorentz.Errors: instance Lorentz.Errors.ErrorHasDoc Lorentz.Errors.UnspecifiedError
+ Lorentz.Errors: instance Lorentz.Errors.ErrorHasDoc Michelson.Text.MText
+ Lorentz.Errors: instance Lorentz.Errors.IsError Lorentz.Errors.UnspecifiedError
+ Lorentz.Errors: instance Lorentz.Errors.IsError Michelson.Text.MText
+ Lorentz.Errors: instance Michelson.Doc.DocItem Lorentz.Errors.DError
+ Lorentz.Errors: instance Michelson.Doc.DocItem Lorentz.Errors.DThrows
+ Lorentz.Errors: instance Michelson.Typed.Haskell.Value.IsoValue Lorentz.Errors.UnspecifiedError
+ Lorentz.Errors: isoErrorFromVal :: (Typeable t, Typeable (ToT e), IsoValue e) => Value t -> Either Text e
+ Lorentz.Errors: isoErrorToVal :: (KnownError e, IsoValue e) => e -> (forall t. ErrorScope t => Value t -> r) -> r
+ Lorentz.Errors: type family CustomErrorNoIsoValue a
+ Lorentz.Errors: typeDocMdDescriptionReferToError :: forall e. IsError e => Markdown
+ Lorentz.Errors.Common: instance Formatting.Buildable.Buildable (Lorentz.Errors.CustomError "senderIsNotAdmin")
+ Lorentz.Errors.Common: instance Lorentz.Errors.CustomErrorHasDoc "senderIsNotAdmin"
+ Lorentz.Errors.Numeric: addNewErrorTags :: ErrorTagMap -> HashSet MText -> ErrorTagMap
+ Lorentz.Errors.Numeric: applyErrorTagMap :: HasCallStack => ErrorTagMap -> (inp :-> out) -> inp :-> out
+ Lorentz.Errors.Numeric: buildErrorTagMap :: HashSet MText -> ErrorTagMap
+ Lorentz.Errors.Numeric: errorFromValNumeric :: (Typeable t, SingI t, IsError e) => ErrorTagMap -> Value t -> Either Text e
+ Lorentz.Errors.Numeric: gatherErrorTags :: (inp :-> out) -> HashSet MText
+ Lorentz.Errors.Numeric: type ErrorTagMap = Bimap Natural MText
+ Lorentz.Errors.Numeric: useNumericErrors :: HasCallStack => (inp :-> out) -> (inp :-> out, ErrorTagMap)
+ Lorentz.Extensible: ArgumentUnpackFailed :: ExtConversionError
+ Lorentz.Extensible: ConstructorIndexNotFound :: Natural -> ExtConversionError
+ Lorentz.Extensible: Extensible :: (Natural, ByteString) -> Extensible x
+ Lorentz.Extensible: class Typeable x => ExtensibleHasDoc x
+ Lorentz.Extensible: data ExtConversionError
+ Lorentz.Extensible: extensibleDocDependencies :: (ExtensibleHasDoc x, Generic x, GTypeHasDoc (Rep x)) => Proxy x -> [SomeTypeWithDoc]
+ Lorentz.Extensible: extensibleDocMdDescription :: ExtensibleHasDoc x => Markdown
+ Lorentz.Extensible: extensibleDocName :: ExtensibleHasDoc x => Proxy x -> Text
+ Lorentz.Extensible: fromExtVal :: ExtVal a => Extensible a -> Either ExtConversionError a
+ Lorentz.Extensible: instance ('Lorentz.Extensible.Ctor n name 'Michelson.Typed.Haskell.Instr.Sum.NoFields Data.Type.Equality.~ Lorentz.Extensible.LookupCtor name (Lorentz.Extensible.EnumerateCtors (Lorentz.Extensible.GetCtors t)), GHC.TypeNats.KnownNat n) => Lorentz.Extensible.GExtVal t (GHC.Generics.C1 ('GHC.Generics.MetaCons name _1 _2) GHC.Generics.U1)
+ Lorentz.Extensible: instance (GHC.TypeNats.KnownNat pos, GHC.TypeLits.KnownSymbol name, Michelson.Typed.Haskell.Doc.TypeHasDoc param, param Data.Type.Equality.~ Michelson.Typed.Haskell.Instr.Sum.ExtractCtorField field) => Lorentz.Extensible.DocumentCtor ('Lorentz.Extensible.Ctor pos name field)
+ Lorentz.Extensible: instance (Lorentz.Constraints.NiceFullPackedValue param, 'Lorentz.Extensible.Ctor n name ('Michelson.Typed.Haskell.Instr.Sum.OneField param) Data.Type.Equality.~ Lorentz.Extensible.LookupCtor name (Lorentz.Extensible.EnumerateCtors (Lorentz.Extensible.GetCtors t)), GHC.TypeNats.KnownNat n) => Lorentz.Extensible.GExtVal t (GHC.Generics.C1 ('GHC.Generics.MetaCons name _1 _2) (GHC.Generics.S1 _3 (GHC.Generics.Rec0 param)))
+ Lorentz.Extensible: instance (Lorentz.Extensible.ExtensibleHasDoc x, Util.Type.ReifyList Lorentz.Extensible.DocumentCtor (Lorentz.Extensible.EnumerateCtors (Lorentz.Extensible.GetCtors x))) => Michelson.Typed.Haskell.Doc.TypeHasDoc (Lorentz.Extensible.Extensible x)
+ Lorentz.Extensible: instance Formatting.Buildable.Buildable Lorentz.Extensible.ExtConversionError
+ Lorentz.Extensible: instance GHC.Classes.Eq Lorentz.Extensible.ExtConversionError
+ Lorentz.Extensible: instance GHC.Show.Show Lorentz.Extensible.ExtConversionError
+ Lorentz.Extensible: instance Lorentz.Constraints.NicePackedValue param => Lorentz.Extensible.WrapExt ('Michelson.Typed.Haskell.Instr.Sum.OneField param)
+ Lorentz.Extensible: instance Lorentz.Extensible.WrapExt 'Michelson.Typed.Haskell.Instr.Sum.NoFields
+ Lorentz.Extensible: instance forall k (t :: k) (x :: * -> *) (i :: GHC.Generics.Meta). Lorentz.Extensible.GExtVal t x => Lorentz.Extensible.GExtVal t (GHC.Generics.D1 i x)
+ Lorentz.Extensible: instance forall k (t :: k) (x :: * -> *) (y :: * -> *). (Lorentz.Extensible.GExtVal t x, Lorentz.Extensible.GExtVal t y) => Lorentz.Extensible.GExtVal t (x GHC.Generics.:+: y)
+ Lorentz.Extensible: instance forall k (x :: k). GHC.Classes.Eq (Lorentz.Extensible.Extensible x)
+ Lorentz.Extensible: instance forall k (x :: k). GHC.Generics.Generic (Lorentz.Extensible.Extensible x)
+ Lorentz.Extensible: instance forall k (x :: k). GHC.Show.Show (Lorentz.Extensible.Extensible x)
+ Lorentz.Extensible: instance forall k (x :: k). Michelson.Typed.Haskell.Value.IsoValue (Lorentz.Extensible.Extensible x)
+ Lorentz.Extensible: newtype Extensible x
+ Lorentz.Extensible: toExtVal :: ExtVal a => a -> Extensible a
+ Lorentz.Extensible: type ExtVal x = (Generic x, GExtVal x (Rep x))
+ Lorentz.Extensible: type WrapExtC t n name field s = ( 'Ctor n name field ~ LookupCtor name (EnumerateCtors (GetCtors t)), WrapExt field, KnownNat n)
+ Lorentz.Extensible: wrapExt :: forall t (n :: Nat) name field s. WrapExtC t n name field s => Label ("c" `AppendSymbol` name) -> AppendCtorField field s :-> (Extensible t : s)
+ Lorentz.Instr: apply :: forall a b c s. NiceConstant a => (a & (Lambda (a, b) c & s)) :-> (Lambda b c & s)
+ Lorentz.Instr: chainId :: s :-> (ChainId & s)
+ Lorentz.Instr: dig :: forall (n :: Nat) inp out a. ConstraintDIGLorentz (ToPeano n) inp out a => inp :-> out
+ Lorentz.Instr: digPeano :: forall (n :: Peano) inp out a. ConstraintDIGLorentz n inp out a => inp :-> out
+ Lorentz.Instr: dipN :: forall (n :: Nat) (inp :: [Type]) (out :: [Type]) (s :: [Type]) (s' :: [Type]). ConstraintDIPNLorentz (ToPeano n) inp out s s' => (s :-> s') -> inp :-> out
+ Lorentz.Instr: dipNPeano :: forall (n :: Peano) (inp :: [Type]) (out :: [Type]) (s :: [Type]) (s' :: [Type]). ConstraintDIPNLorentz n inp out s s' => (s :-> s') -> inp :-> out
+ Lorentz.Instr: dropN :: forall (n :: Nat) (s :: [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
+ Lorentz.Instr: dug :: forall (n :: Nat) inp out a. ConstraintDUGLorentz (ToPeano n) inp out a => inp :-> out
+ Lorentz.Instr: emptyBigMap :: (KnownCValue k, KnownValue v) => s :-> (BigMap k v & s)
+ Lorentz.Instr: execute :: forall i o s. Each [KnownList, ZipInstr] [i, o] => ((i :-> o) : (i ++ s)) :-> (o ++ s)
+ Lorentz.Instr: framed :: forall s i o. (KnownList i, KnownList o) => (i :-> o) -> (i ++ s) :-> (o ++ s)
+ Lorentz.Instr: instance Lorentz.Instr.NonZero GHC.Integer.Type.Integer
+ Lorentz.Instr: instance Lorentz.Instr.NonZero GHC.Natural.Natural
+ Lorentz.Instr: nonZero :: NonZero t => (t : s) :-> (Maybe t : s)
+ Lorentz.Instr: type ConstraintDIPNLorentz (n :: Peano) (inp :: [Type]) (out :: [Type]) (s :: [Type]) (s' :: [Type]) = (ConstraintDIPN n (ToTs inp) (ToTs out) (ToTs s) (ToTs s'), ConstraintDIPN' Type n inp out s s')
+ Lorentz.Macro: buildView :: (a -> Builder) -> View a r -> Builder
+ Lorentz.Macro: buildViewTuple :: TupleF a => View a r -> Builder
+ Lorentz.Macro: framedN :: forall n nNat s i i' o o'. (nNat ~ ToPeano n, i' ~ Take nNat i, s ~ Drop nNat i, i ~ (i' ++ s), o ~ (o' ++ s), KnownList i', KnownList o') => (i' :-> o') -> i :-> o
+ Lorentz.Macro: instance (Data.Typeable.Internal.Typeable r, Lorentz.Constraints.NiceConstant r, Lorentz.Errors.ErrorHasDoc (Lorentz.Macro.VoidResult r)) => Lorentz.Errors.IsError (Lorentz.Macro.VoidResult r)
+ Lorentz.Macro: instance (Michelson.Typed.Haskell.Doc.TypeHasDoc r, Lorentz.Errors.IsError (Lorentz.Macro.VoidResult r)) => Michelson.Typed.Haskell.Doc.TypeHasDoc (Lorentz.Macro.VoidResult r)
+ Lorentz.Macro: instance Formatting.Buildable.Buildable (Lorentz.Macro.View () r)
+ Lorentz.Macro: instance Formatting.Buildable.Buildable a => Formatting.Buildable.Buildable (Lorentz.Macro.View a r)
+ Lorentz.Macro: instance Formatting.Buildable.Buildable a => Formatting.Buildable.Buildable (Lorentz.Macro.Void_ a b)
+ Lorentz.Macro: instance GHC.Classes.Eq a => GHC.Classes.Eq (Lorentz.Macro.View a r)
+ Lorentz.Macro: instance GHC.Generics.Generic (Lorentz.Macro.VoidResult r)
+ Lorentz.Macro: instance GHC.Show.Show a => GHC.Show.Show (Lorentz.Macro.View a r)
+ Lorentz.Macro: instance Lorentz.Errors.CustomErrorNoIsoValue (Lorentz.Macro.VoidResult r) => Michelson.Typed.Haskell.Value.IsoValue (Lorentz.Macro.VoidResult r)
+ Lorentz.Macro: instance Lorentz.Macro.ConstraintDuupXLorentz ('Data.Vinyl.TypeLevel.S ('Data.Vinyl.TypeLevel.S n)) s a s1 tail => Lorentz.Macro.DuupX ('Data.Vinyl.TypeLevel.S ('Data.Vinyl.TypeLevel.S ('Data.Vinyl.TypeLevel.S n))) s a s1 tail
+ Lorentz.Macro: instance Michelson.Typed.Haskell.Doc.TypeHasDoc r => Lorentz.Errors.ErrorHasDoc (Lorentz.Macro.VoidResult r)
+ Lorentz.Macro: instance Universum.TypeOps.Each '[Data.Typeable.Internal.Typeable, Michelson.Typed.Haskell.Doc.TypeHasDoc] '[a, r] => Michelson.Typed.Haskell.Doc.TypeHasDoc (Lorentz.Macro.View a r)
+ Lorentz.Macro: instance Universum.TypeOps.Each '[Data.Typeable.Internal.Typeable, Michelson.Typed.Haskell.Doc.TypeHasDoc] '[a, r] => Michelson.Typed.Haskell.Doc.TypeHasDoc (Lorentz.Macro.Void_ a r)
+ Lorentz.Macro: instance forall k1 k2 (s :: [*]) a (xs :: [*]) (s1 :: k2) (tail :: k1). (s Data.Type.Equality.~ (a : xs)) => Lorentz.Macro.DuupX ('Data.Vinyl.TypeLevel.S 'Data.Vinyl.TypeLevel.Z) s a s1 tail
+ Lorentz.Macro: instance forall k1 k2 b a (xs :: [*]) (s1 :: k2) (tail :: k1). Lorentz.Macro.DuupX ('Data.Vinyl.TypeLevel.S ('Data.Vinyl.TypeLevel.S 'Data.Vinyl.TypeLevel.Z)) (b : a : xs) a s1 tail
+ Lorentz.Macro: mkView :: ToContractRef r contract => a -> contract -> View a r
+ Lorentz.Macro: pickFutureContract :: NiceParameter p => (FutureContract p : s) :-> (Maybe (ContractRef p) : s)
+ Lorentz.Macro: pushContractRef :: NiceParameter arg => (forall s0. (Address : s) :-> s0) -> ContractRef arg -> s :-> (ContractRef arg : s)
+ Lorentz.Pack: lPackValue :: forall a. NicePackedValue a => a -> ByteString
+ Lorentz.Pack: lUnpackValue :: forall a. NiceUnpackedValue a => ByteString -> Either UnpackError a
+ Lorentz.Prelude: (.) :: () => (b -> c) -> (a -> b) -> a -> c
+ Lorentz.Prelude: Just :: a -> Maybe a
+ Lorentz.Prelude: Left :: a -> Either a b
+ Lorentz.Prelude: Nothing :: Maybe a
+ Lorentz.Prelude: Proxy :: Proxy
+ Lorentz.Prelude: Right :: b -> Either a b
+ Lorentz.Prelude: data Either a b
+ Lorentz.Prelude: data Maybe a
+ Lorentz.Prelude: data Proxy (t :: k) :: forall k. () => k -> Type
+ Lorentz.Prelude: error :: HasCallStack => Text -> a
+ Lorentz.Prelude: infixr 9 .
+ Lorentz.Print: printLorentzContract :: forall cp st. (NiceParameter cp, NiceStorage st, ParameterEntryPoints cp) => Bool -> Contract cp st -> LText
+ Lorentz.Print: printLorentzValue :: forall v. NicePrintedValue v => Bool -> v -> LText
+ Lorentz.Run: analyzeLorentz :: (inp :-> out) -> AnalyzerRes
+ Lorentz.Run: compileLorentz :: (inp :-> out) -> Instr (ToTs inp) (ToTs out)
+ Lorentz.Run: compileLorentzContract :: forall cp st. (NiceParameter cp, NiceStorage st, ParameterEntryPoints cp) => Contract cp st -> FullContract (ToT cp) (ToT st)
+ Lorentz.Run: interpretLorentzInstr :: (IsoValuesStack inp, IsoValuesStack out) => ContractEnv -> (inp :-> out) -> Rec Identity inp -> Either MichelsonFailed (Rec Identity out)
+ Lorentz.Run: interpretLorentzLambda :: (IsoValue inp, IsoValue out) => ContractEnv -> Lambda inp out -> inp -> Either MichelsonFailed out
+ Lorentz.Store: instance (Lorentz.Store.StoreMemC store name, Lorentz.Store.StoreGetC store name, Lorentz.Store.StoreUpdateC store name, key Data.Type.Equality.~ Lorentz.Store.GetStoreKey store name, value Data.Type.Equality.~ Lorentz.Store.GetStoreValue store name) => Lorentz.StoreClass.StoreHasSubmap (Lorentz.Store.Store store) name key value
+ Lorentz.Store: instance (Lorentz.Store.StoreMemC store name, Lorentz.Store.StoreGetC store name, Lorentz.Store.StoreUpdateC store name, key Data.Type.Equality.~ Lorentz.Store.GetStoreKey store name, value Data.Type.Equality.~ Lorentz.Store.GetStoreValue store name, Michelson.Typed.Haskell.Value.IsoValue other) => Lorentz.StoreClass.StoreHasSubmap (Lorentz.Store.StorageSkeleton store other) name key value
+ Lorentz.Store: instance (Lorentz.StoreClass.StoreHasField other fname ftype, Michelson.Typed.Haskell.Value.IsoValue store, Michelson.Typed.Haskell.Value.IsoValue other) => Lorentz.StoreClass.StoreHasField (Lorentz.Store.StorageSkeleton store other) fname ftype
+ Lorentz.Store: storeKeyValueList :: forall name store key value. StorePieceC store name key value => Label name -> [(key, value)] -> Store store
+ Lorentz.Store: storeUpdate :: forall store name s. StoreUpdateC store name => Label name -> (GetStoreKey store name : (Maybe (GetStoreValue store name) : (Store store : s))) :-> (Store store : s)
+ Lorentz.Store: type StoreUpdateC store name = (KnownValue store, StoreOpC store name, InstrWrapC store name, CtorHasOnlyField name store (GetStoreKey store name |-> GetStoreValue store name))
+ Lorentz.StoreClass: StoreFieldOps :: (forall s. Label fname -> (store : s) :-> (ftype : s)) -> (forall s. Label fname -> (ftype : (store : s)) :-> (store : s)) -> StoreFieldOps store fname ftype
+ Lorentz.StoreClass: StoreSubmapOps :: (forall s. Label mname -> (key : (store : s)) :-> (Bool : s)) -> (forall s. Label mname -> (key : (store : s)) :-> (Maybe value : s)) -> (forall s. Label mname -> (key : (Maybe value : (store : s))) :-> (store : s)) -> (forall s. Maybe (Label mname -> (key : (store : s)) :-> (store : s))) -> (forall s. Maybe (Label mname -> (key : (value : (store : s))) :-> (store : s))) -> StoreSubmapOps store mname key value
+ Lorentz.StoreClass: [sopDelete] :: StoreSubmapOps store mname key value -> forall s. Maybe (Label mname -> (key : (store : s)) :-> (store : s))
+ Lorentz.StoreClass: [sopGet] :: StoreSubmapOps store mname key value -> forall s. Label mname -> (key : (store : s)) :-> (Maybe value : s)
+ Lorentz.StoreClass: [sopInsert] :: StoreSubmapOps store mname key value -> forall s. Maybe (Label mname -> (key : (value : (store : s))) :-> (store : s))
+ Lorentz.StoreClass: [sopMem] :: StoreSubmapOps store mname key value -> forall s. Label mname -> (key : (store : s)) :-> (Bool : s)
+ Lorentz.StoreClass: [sopSetField] :: StoreFieldOps store fname ftype -> forall s. Label fname -> (ftype : (store : s)) :-> (store : s)
+ Lorentz.StoreClass: [sopToField] :: StoreFieldOps store fname ftype -> forall s. Label fname -> (store : s) :-> (ftype : s)
+ Lorentz.StoreClass: [sopUpdate] :: StoreSubmapOps store mname key value -> forall s. Label mname -> (key : (Maybe value : (store : s))) :-> (store : s)
+ Lorentz.StoreClass: class StoreHasField store fname ftype | store fname -> ftype
+ Lorentz.StoreClass: class StoreHasSubmap store mname key value | store mname -> key value
+ Lorentz.StoreClass: composeStoreFieldOps :: Label nameInStore -> StoreFieldOps store nameInStore substore -> StoreFieldOps substore nameInSubstore field -> StoreFieldOps store nameInSubstore field
+ Lorentz.StoreClass: composeStoreSubmapOps :: Label nameInStore -> StoreFieldOps store nameInStore substore -> StoreSubmapOps substore mname key value -> StoreSubmapOps store mname key value
+ Lorentz.StoreClass: data StoreFieldOps store fname ftype
+ Lorentz.StoreClass: data StoreSubmapOps store mname key value
+ Lorentz.StoreClass: data k ~> v
+ Lorentz.StoreClass: infix 9 ~>
+ Lorentz.StoreClass: instance (key Data.Type.Equality.~ key', value Data.Type.Equality.~ value', Michelson.Typed.Haskell.Value.IsComparable key) => Lorentz.StoreClass.StoreHasSubmap (Data.Map.Internal.Map key' value') name key value
+ Lorentz.StoreClass: instance (key Data.Type.Equality.~ key', value Data.Type.Equality.~ value', Michelson.Typed.Haskell.Value.IsComparable key) => Lorentz.StoreClass.StoreHasSubmap (Michelson.Typed.Haskell.Value.BigMap key' value') name key value
+ Lorentz.StoreClass: stDelete :: forall store mname key value s. (StoreHasSubmap store mname key value, KnownValue value) => Label mname -> (key : (store : s)) :-> (store : s)
+ Lorentz.StoreClass: stGet :: StoreHasSubmap store mname key value => Label mname -> (key : (store : s)) :-> (Maybe value : s)
+ Lorentz.StoreClass: stGetField :: StoreHasField store fname ftype => Label fname -> (store : s) :-> (ftype : (store : s))
+ Lorentz.StoreClass: stInsert :: StoreHasSubmap store mname key value => Label mname -> (key : (value : (store : s))) :-> (store : s)
+ Lorentz.StoreClass: stInsertNew :: StoreHasSubmap store mname key value => Label mname -> (forall s0 any. (key : s0) :-> any) -> (key : (value : (store : s))) :-> (store : s)
+ Lorentz.StoreClass: stMem :: StoreHasSubmap store mname key value => Label mname -> (key : (store : s)) :-> (Bool : s)
+ Lorentz.StoreClass: stSetField :: StoreHasField store fname ftype => Label fname -> (ftype : (store : s)) :-> (store : s)
+ Lorentz.StoreClass: stToField :: StoreHasField store fname ftype => Label fname -> (store : s) :-> (ftype : s)
+ Lorentz.StoreClass: stUpdate :: StoreHasSubmap store mname key value => Label mname -> (key : (Maybe value : (store : s))) :-> (store : s)
+ Lorentz.StoreClass: storeFieldOps :: StoreHasField store fname ftype => StoreFieldOps store fname ftype
+ Lorentz.StoreClass: storeFieldOpsADT :: HasFieldOfType dt fname ftype => StoreFieldOps dt fname ftype
+ Lorentz.StoreClass: storeFieldOpsDeeper :: (HasFieldOfType storage fieldsPartName fields, StoreHasField fields fname ftype) => Label fieldsPartName -> StoreFieldOps storage fname ftype
+ Lorentz.StoreClass: storeFieldOpsReferTo :: Label name -> StoreFieldOps storage name field -> StoreFieldOps storage desiredName field
+ Lorentz.StoreClass: storeSubmapOps :: StoreHasSubmap store mname key value => StoreSubmapOps store mname key value
+ Lorentz.StoreClass: storeSubmapOpsDeeper :: (HasFieldOfType storage bigMapPartName fields, StoreHasSubmap fields mname key value) => Label bigMapPartName -> StoreSubmapOps storage mname key value
+ Lorentz.StoreClass: storeSubmapOpsReferTo :: Label name -> StoreSubmapOps storage name key value -> StoreSubmapOps storage desiredName key value
+ Lorentz.StoreClass: type family StorageContains store (content :: [NamedField]) :: Constraint
+ Lorentz.Test: (?-) :: Text -> a -> (Text, a)
+ Lorentz.Test: CustomValidationError :: Text -> ValidationError
+ Lorentz.Test: UnexpectedUpdates :: NonEmpty GStateUpdate -> ValidationError
+ Lorentz.Test: branchout :: HasCallStack => [(Text, IntegrationalScenario)] -> IntegrationalScenario
+ Lorentz.Test: contractConsumer :: Contract cp [cp]
+ Lorentz.Test: expectNoStorageUpdates :: SuccessValidator
+ Lorentz.Test: expectNoUpdates :: SuccessValidator
+ Lorentz.Test: infixr 0 ?-
+ Lorentz.Test: lExpectCustomError :: forall tag arg. (IsError (CustomError tag), arg ~ ErrorArg tag, Eq arg) => Label tag -> arg -> InterpreterError -> Bool
+ Lorentz.Test: lExpectCustomErrorNumeric :: forall tag arg. (IsError (CustomError tag), arg ~ ErrorArg tag, Eq arg) => ErrorTagMap -> Label tag -> arg -> InterpreterError -> Bool
+ Lorentz.Test: lExpectCustomErrorNumeric_ :: forall tag. (IsError (CustomError tag), ErrorArg tag ~ ()) => ErrorTagMap -> Label tag -> InterpreterError -> Bool
+ Lorentz.Test: lExpectCustomError_ :: forall tag. (IsError (CustomError tag), ErrorArg tag ~ ()) => Label tag -> InterpreterError -> Bool
+ Lorentz.Test: lExpectError :: forall e. IsError e => (e -> Bool) -> InterpreterError -> Bool
+ Lorentz.Test: lExpectErrorNumeric :: forall e. IsError e => ErrorTagMap -> (e -> Bool) -> InterpreterError -> Bool
+ Lorentz.Test: offshoot :: Text -> IntegrationalScenario -> IntegrationalScenarioM ()
+ Lorentz.Test: rewindTime :: Integer -> IntegrationalScenarioM ()
+ Lorentz.Test: setChainId :: ChainId -> IntegrationalScenarioM ()
+ Lorentz.Test.Consumer: contractConsumer :: Contract cp [cp]
+ Lorentz.Test.Integrational: (?-) :: Text -> a -> (Text, a)
+ Lorentz.Test.Integrational: CustomValidationError :: Text -> ValidationError
+ Lorentz.Test.Integrational: UnexpectedUpdates :: NonEmpty GStateUpdate -> ValidationError
+ Lorentz.Test.Integrational: branchout :: HasCallStack => [(Text, IntegrationalScenario)] -> IntegrationalScenario
+ Lorentz.Test.Integrational: expectNoStorageUpdates :: SuccessValidator
+ Lorentz.Test.Integrational: expectNoUpdates :: SuccessValidator
+ Lorentz.Test.Integrational: infixr 0 ?-
+ Lorentz.Test.Integrational: lExpectCustomError :: forall tag arg. (IsError (CustomError tag), arg ~ ErrorArg tag, Eq arg) => Label tag -> arg -> InterpreterError -> Bool
+ Lorentz.Test.Integrational: lExpectCustomErrorNumeric :: forall tag arg. (IsError (CustomError tag), arg ~ ErrorArg tag, Eq arg) => ErrorTagMap -> Label tag -> arg -> InterpreterError -> Bool
+ Lorentz.Test.Integrational: lExpectCustomErrorNumeric_ :: forall tag. (IsError (CustomError tag), ErrorArg tag ~ ()) => ErrorTagMap -> Label tag -> InterpreterError -> Bool
+ Lorentz.Test.Integrational: lExpectCustomError_ :: forall tag. (IsError (CustomError tag), ErrorArg tag ~ ()) => Label tag -> InterpreterError -> Bool
+ Lorentz.Test.Integrational: lExpectError :: forall e. IsError e => (e -> Bool) -> InterpreterError -> Bool
+ Lorentz.Test.Integrational: lExpectErrorNumeric :: forall e. IsError e => ErrorTagMap -> (e -> Bool) -> InterpreterError -> Bool
+ Lorentz.Test.Integrational: offshoot :: Text -> IntegrationalScenario -> IntegrationalScenarioM ()
+ Lorentz.Test.Integrational: rewindTime :: Integer -> IntegrationalScenarioM ()
+ Lorentz.Test.Integrational: setChainId :: ChainId -> IntegrationalScenarioM ()
+ Lorentz.Test.Integrational: tExpectStorageConst :: forall st. StorageScope st => Address -> Value st -> SuccessValidator
+ Lorentz.Test.Integrational: tOriginate :: (ParameterScope cp, StorageScope st) => Contract cp st -> Text -> Value st -> Mutez -> IntegrationalScenarioM Address
+ Lorentz.Test.Integrational: tTransfer :: forall cp. ParameterScope cp => ("from" :! Address) -> ("to" :! Address) -> Mutez -> Value cp -> IntegrationalScenarioM ()
+ Lorentz.TestScenario: instance GHC.Generics.Generic Lorentz.TestScenario.Parameter
+ Lorentz.TestScenario: instance Michelson.Typed.Haskell.Value.IsoValue Lorentz.TestScenario.Parameter
+ Lorentz.TestScenario: showTestScenario :: (Buildable param, NicePrintedValue param) => TestScenario param -> Text
+ Lorentz.TestScenario: type TestScenario param = [(Address, param)]
+ Lorentz.UParam: ArgumentUnpackFailed :: EntryPointLookupError
+ Lorentz.UParam: NoSuchEntryPoint :: MText -> EntryPointLookupError
+ Lorentz.UParam: UParamUnsafe :: (MText, ByteString) -> UParam
+ Lorentz.UParam: [ConstrainedSome] :: c a => a -> ConstrainedSome c
+ Lorentz.UParam: caseUParam :: (CaseUParam entries, RequireUniqueEntryPoints entries) => Rec (CaseClauseU inp out) entries -> UParamFallback inp out -> (UParam entries : inp) :-> out
+ Lorentz.UParam: caseUParamT :: forall entries inp out clauses. (clauses ~ Rec (CaseClauseU inp out) entries, RecFromTuple clauses, CaseUParam entries) => IsoRecTuple clauses -> UParamFallback inp out -> (UParam entries : inp) :-> out
+ Lorentz.UParam: class CaseUParam (entries :: [EntryPointKind])
+ Lorentz.UParam: class UnpackUParam (c :: Type -> Constraint) entries
+ Lorentz.UParam: data ConstrainedSome (c :: Type -> Constraint)
+ Lorentz.UParam: data EntryPointLookupError
+ Lorentz.UParam: instance (GHC.TypeLits.KnownSymbol name, Lorentz.Constraints.NicePackedValue a) => Lorentz.UParam.GUParamLinearize (GHC.Generics.C1 ('GHC.Generics.MetaCons name _1 _2) (GHC.Generics.S1 si (GHC.Generics.Rec0 a)))
+ Lorentz.UParam: instance (GHC.TypeLits.KnownSymbol name, Lorentz.UParam.CaseUParam entries, Lorentz.Constraints.NiceUnpackedValue arg) => Lorentz.UParam.CaseUParam ((name Lorentz.UParam.?: arg) : entries)
+ Lorentz.UParam: instance (GHC.TypeLits.KnownSymbol name, Lorentz.UParam.UnpackUParam c entries, Lorentz.Constraints.NiceUnpackedValue arg, c arg) => Lorentz.UParam.UnpackUParam c ((name Lorentz.UParam.?: arg) : entries)
+ Lorentz.UParam: instance (Lorentz.UParam.GUParamLinearize x, Lorentz.UParam.GUParamLinearize y) => Lorentz.UParam.GUParamLinearize (x GHC.Generics.:+: y)
+ Lorentz.UParam: instance (TypeError ...) => Lorentz.UParam.GUParamLinearize (GHC.Generics.C1 i (x GHC.Generics.:*: y))
+ Lorentz.UParam: instance (TypeError ...) => Lorentz.UParam.GUParamLinearize (GHC.Generics.C1 i GHC.Generics.U1)
+ Lorentz.UParam: instance (name Data.Type.Equality.~ name', body Data.Type.Equality.~ ((arg : inp) Lorentz.Base.:-> out)) => Lorentz.ADT.CaseArrow name' body (Lorentz.UParam.CaseClauseU inp out '(name, arg))
+ Lorentz.UParam: instance Data.Typeable.Internal.Typeable interface => Michelson.Typed.Haskell.Doc.TypeHasDoc (Lorentz.UParam.UParam interface)
+ Lorentz.UParam: instance Formatting.Buildable.Buildable (Lorentz.Errors.CustomError "uparamArgumentUnpackFailed")
+ Lorentz.UParam: instance Formatting.Buildable.Buildable (Lorentz.Errors.CustomError "uparamNoSuchEntryPoint")
+ Lorentz.UParam: instance Formatting.Buildable.Buildable (Lorentz.UParam.ConstrainedSome Formatting.Buildable.Buildable)
+ Lorentz.UParam: instance Formatting.Buildable.Buildable Lorentz.UParam.EntryPointLookupError
+ Lorentz.UParam: instance GHC.Classes.Eq (Lorentz.UParam.UParam entries)
+ Lorentz.UParam: instance GHC.Classes.Eq Lorentz.UParam.EntryPointLookupError
+ Lorentz.UParam: instance GHC.Generics.Generic (Lorentz.UParam.UParam entries)
+ Lorentz.UParam: instance GHC.Generics.Generic Lorentz.UParam.EntryPointLookupError
+ Lorentz.UParam: instance GHC.Show.Show (Lorentz.UParam.ConstrainedSome GHC.Show.Show)
+ Lorentz.UParam: instance GHC.Show.Show (Lorentz.UParam.UParam entries)
+ Lorentz.UParam: instance GHC.Show.Show Lorentz.UParam.EntryPointLookupError
+ Lorentz.UParam: instance Lorentz.Errors.CustomErrorHasDoc "uparamArgumentUnpackFailed"
+ Lorentz.UParam: instance Lorentz.Errors.CustomErrorHasDoc "uparamNoSuchEntryPoint"
+ Lorentz.UParam: instance Lorentz.UParam.CaseUParam '[]
+ Lorentz.UParam: instance Lorentz.UParam.GUParamLinearize x => Lorentz.UParam.GUParamLinearize (GHC.Generics.D1 i x)
+ Lorentz.UParam: instance Lorentz.UParam.UnpackUParam c '[]
+ Lorentz.UParam: instance Michelson.Typed.Haskell.Value.IsoValue (Lorentz.UParam.UParam entries)
+ Lorentz.UParam: mkUParam :: (KnownSymbol name, NicePackedValue a, LookupEntryPoint name entries ~ a, RequireUniqueEntryPoints entries) => Label name -> a -> UParam entries
+ Lorentz.UParam: newtype UParam (entries :: [EntryPointKind])
+ Lorentz.UParam: pbsUParam :: forall ctorName. KnownSymbol ctorName => ParamBuildingStep
+ Lorentz.UParam: type (n :: Symbol) ?: (a :: k) = '(n, a)
+ Lorentz.UParam: type EntryPointKind = (Symbol, Type)
+ Lorentz.UParam: type EntryPointsImpl inp out entries = Rec (CaseClauseU inp out) entries
+ Lorentz.UParam: type UParamFallback inp out = ((MText, ByteString) : inp) :-> out
+ Lorentz.UParam: type UParamLinearize p = (Generic p, GUParamLinearize (Rep p))
+ Lorentz.UParam: type UParamLinearized p = GUParamLinearized (Rep p)
+ Lorentz.UParam: type family RequireUniqueEntryPoints (entries :: [EntryPointKind]) :: Constraint
+ Lorentz.UParam: unpackUParam :: UnpackUParam c entries => UParam entries -> Either EntryPointLookupError (MText, ConstrainedSome c)
+ Lorentz.UParam: unwrapUParam :: (UParam entries : s) :-> ((MText, ByteString) : s)
+ Lorentz.UParam: uparamFallbackFail :: UParamFallback inp out
+ Lorentz.UParam: uparamFromAdt :: UParamLinearize up => up -> UParam (UParamLinearized up)
+ Lorentz.UStore: -- and field value type. Used for error messages.
+ Lorentz.UStore: -- | Display type-level information about UStore field with given marker
+ Lorentz.UStore: MigrationScript :: Lambda UStore_ UStore_ -> MigrationScript
+ Lorentz.UStore: UStoreField :: v -> UStoreFieldExt
+ Lorentz.UStore: UStoreSubMap :: Map k v -> (|~>) k v
+ Lorentz.UStore: [unMigrationScript] :: MigrationScript -> Lambda UStore_ UStore_
+ Lorentz.UStore: [unUStoreField] :: UStoreFieldExt -> v
+ Lorentz.UStore: [unUStoreSubMap] :: (|~>) k v -> Map k v
+ Lorentz.UStore: class KnownUStoreMarker (marker :: UStoreMarkerType) where {
+ Lorentz.UStore: class (Generic template, GUStoreConversible (Rep template)) => UStoreConversible template
+ Lorentz.UStore: data UStore (a :: Type)
+ Lorentz.UStore: data UStoreMigration (oldStore :: Type) (newStore :: Type)
+ Lorentz.UStore: fillUStore :: UStoreConversible template => template -> UStoreMigrationT () template
+ Lorentz.UStore: liftUStore :: (Generic template, RequireAllUniqueFields template) => Label name -> (UStore (GetFieldType template name) : s) :-> (UStore template : s)
+ Lorentz.UStore: migrateAddField :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s. ('(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcAdd field diff, HasUField field fieldTy newTempl) => Label field -> (fieldTy : (MUStore oldTempl newTempl diff touched : s)) :-> (MUStore oldTempl newTempl newDiff (field : touched) : s)
+ Lorentz.UStore: migrateExtractField :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s. ('(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcRemove field diff, HasUField field fieldTy oldTempl, RequireUntouched field (field `IsElem` touched)) => Label field -> (MUStore oldTempl newTempl diff touched : s) :-> (fieldTy : (MUStore oldTempl newTempl newDiff (field : touched) : s))
+ Lorentz.UStore: migrateGetField :: forall field oldTempl newTempl diff touched fieldTy s. (HasUField field fieldTy oldTempl, RequireUntouched field (field `IsElem` touched)) => Label field -> (MUStore oldTempl newTempl diff touched : s) :-> (fieldTy : (MUStore oldTempl newTempl diff touched : s))
+ Lorentz.UStore: migrateOverwriteField :: forall field oldTempl newTempl diff touched fieldTy oldFieldTy marker oldMarker newDiff newDiff0 s. ('(UStoreFieldExt oldMarker oldFieldTy, newDiff0) ~ CoverDiff 'DcRemove field diff, '(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcAdd field newDiff0, HasUField field fieldTy newTempl) => Label field -> (fieldTy : (MUStore oldTempl newTempl diff touched : s)) :-> (MUStore oldTempl newTempl newDiff (field : touched) : s)
+ Lorentz.UStore: migrateRemoveField :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s. ('(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcRemove field diff, HasUField field fieldTy oldTempl) => Label field -> (MUStore oldTempl newTempl diff touched : s) :-> (MUStore oldTempl newTempl newDiff (field : touched) : s)
+ Lorentz.UStore: migrationToLambda :: UStoreMigrationT oldTemplate newTemplate -> Lambda (UStore oldTemplate) (UStore newTemplate)
+ Lorentz.UStore: migrationToScript :: UStoreMigration ot nt -> MigrationScript
+ Lorentz.UStore: mkFieldMarkerUKey :: (KnownUStoreMarker marker, KnownSymbol name) => Label name -> ByteString
+ Lorentz.UStore: mkUStore :: UStoreConversible template => template -> UStore template
+ Lorentz.UStore: mkUStoreMigration :: Lambda (MUStore oldTempl newTempl (BuildDiff oldTempl newTempl) '[]) (MUStore oldTempl newTempl '[] _1) -> UStoreMigrationT oldTempl newTempl
+ Lorentz.UStore: mustoreToOld :: RequireBeInitial touched => (MUStore oldTemplate newTemplate remDiff touched : s) :-> (UStore oldTemplate : s)
+ Lorentz.UStore: newtype MigrationScript
+ Lorentz.UStore: newtype UStoreFieldExt (m :: UStoreMarkerType) (v :: Type)
+ Lorentz.UStore: newtype k |~> v
+ Lorentz.UStore: type GetUStoreField store name = FSValue (GetUStore name store)
+ Lorentz.UStore: type GetUStoreFieldMarker store name = FSMarker (GetUStore name store)
+ Lorentz.UStore: type GetUStoreKey store name = MSKey (GetUStore name store)
+ Lorentz.UStore: type GetUStoreValue store name = MSValue (GetUStore name store)
+ Lorentz.UStore: type HasUField name ty store = (FieldAccessC store name, GetUStoreField store name ~ ty)
+ Lorentz.UStore: type HasUStore name key value store = (KeyAccessC store name, ValueAccessC store name, GetUStoreKey store name ~ key, GetUStoreValue store name ~ value)
+ Lorentz.UStore: type HasUStoreForAllIn store constrained = (Generic store, GHasStoreForAllIn constrained (Rep store))
+ Lorentz.UStore: type InitUStore = UStore ()
+ Lorentz.UStore: type PickMarkedFields marker template = GPickMarkedFields marker (Rep template)
+ Lorentz.UStore: type ShowUStoreField marker v = 'Text "field of type " :<>: 'ShowType v;
+ Lorentz.UStore: type UStoreField = UStoreFieldExt UMarkerPlainField
+ Lorentz.UStore: type UStoreMarkerType = UStoreMarker -> Type
+ Lorentz.UStore: type UStoreMigrationT ot nt = UStoreMigration (UStore ot) (UStore nt)
+ Lorentz.UStore: type family ShowUStoreField marker v :: ErrorMessage;
+ Lorentz.UStore: unliftUStore :: Generic template => Label name -> (UStore template : s) :-> (UStore (GetFieldType template name) : s)
+ Lorentz.UStore: ustoreDecompose :: forall template. UStoreConversible template => UStore template -> Either Text (UStoreContent, template)
+ Lorentz.UStore: ustoreDecomposeFull :: forall template. UStoreConversible template => UStore template -> Either Text template
+ Lorentz.UStore: ustoreDelete :: forall store name s. KeyAccessC store name => Label name -> (GetUStoreKey store name : (UStore store : s)) :-> (UStore store : s)
+ Lorentz.UStore: ustoreGet :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (GetUStoreKey store name : (UStore store : s)) :-> (Maybe (GetUStoreValue store name) : s)
+ Lorentz.UStore: ustoreGetField :: forall store name s. FieldAccessC store name => Label name -> (UStore store : s) :-> (GetUStoreField store name : (UStore store : s))
+ Lorentz.UStore: ustoreInsert :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (GetUStoreKey store name : (GetUStoreValue store name : (UStore store : s))) :-> (UStore store : s)
+ Lorentz.UStore: ustoreInsertNew :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (forall s0 any. (GetUStoreKey store name : s0) :-> any) -> (GetUStoreKey store name : (GetUStoreValue store name : (UStore store : s))) :-> (UStore store : s)
+ Lorentz.UStore: ustoreMem :: forall store name s. KeyAccessC store name => Label name -> (GetUStoreKey store name : (UStore store : s)) :-> (Bool : s)
+ Lorentz.UStore: ustoreSetField :: forall store name s. FieldAccessC store name => Label name -> (GetUStoreField store name : (UStore store : s)) :-> (UStore store : s)
+ Lorentz.UStore: ustoreToField :: forall store name s. FieldAccessC store name => Label name -> (UStore store : s) :-> (GetUStoreField store name : s)
+ Lorentz.UStore: ustoreUpdate :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (GetUStoreKey store name : (Maybe (GetUStoreValue store name) : (UStore store : s))) :-> (UStore store : s)
+ Lorentz.UStore: }
+ Lorentz.UStore.Common: fieldNameToMText :: forall field. KnownSymbol field => MText
+ Lorentz.UStore.Haskell: class (Generic template, GUStoreConversible (Rep template)) => UStoreConversible template
+ Lorentz.UStore.Haskell: fillUStore :: UStoreConversible template => template -> UStoreMigrationT () template
+ Lorentz.UStore.Haskell: fillUStoreMigrationBlock :: (UStoreConversible template, allFieldsExp ~ AllUStoreFieldsF template, newDiff ~ FillingNewDiff template diff, newTouched ~ FillingNewTouched template touched, PatternMatchL newDiff, PatternMatchL newTouched) => template -> MigrationBlocks oldTempl newTempl diff touched newDiff newTouched
+ Lorentz.UStore.Haskell: instance (GHC.Generics.Generic template, Lorentz.UStore.Haskell.GUStoreConversible (GHC.Generics.Rep template)) => Lorentz.UStore.Haskell.UStoreConversible template
+ Lorentz.UStore.Haskell: instance (Lorentz.Constraints.NiceFullPackedValue k, Lorentz.Constraints.NiceFullPackedValue v, GHC.TypeLits.KnownSymbol fieldName, GHC.Classes.Ord k) => Lorentz.UStore.Haskell.GUStoreConversible (GHC.Generics.S1 ('GHC.Generics.MetaSel ('GHC.Maybe.Just fieldName) _1 _2 _3) (GHC.Generics.Rec0 (k Lorentz.UStore.Types.|~> v)))
+ Lorentz.UStore.Haskell: instance (Lorentz.Constraints.NiceFullPackedValue v, Lorentz.UStore.Types.KnownUStoreMarker m, GHC.TypeLits.KnownSymbol fieldName) => Lorentz.UStore.Haskell.GUStoreConversible (GHC.Generics.S1 ('GHC.Generics.MetaSel ('GHC.Maybe.Just fieldName) _1 _2 _3) (GHC.Generics.Rec0 (Lorentz.UStore.Types.UStoreFieldExt m v)))
+ Lorentz.UStore.Haskell: instance (Lorentz.UStore.Haskell.GUStoreConversible x, Lorentz.UStore.Haskell.GUStoreConversible y) => Lorentz.UStore.Haskell.GUStoreConversible (x GHC.Generics.:*: y)
+ Lorentz.UStore.Haskell: instance (TypeError ...) => Lorentz.UStore.Haskell.GUStoreConversible (x GHC.Generics.:+: y)
+ Lorentz.UStore.Haskell: instance (TypeError ...) => Lorentz.UStore.Haskell.GUStoreConversible GHC.Generics.V1
+ Lorentz.UStore.Haskell: instance GHC.Generics.Generic Lorentz.UStore.Haskell.MyStoreTemplate
+ Lorentz.UStore.Haskell: instance GHC.Generics.Generic Lorentz.UStore.Haskell.MyStoreTemplateBig
+ Lorentz.UStore.Haskell: instance Lorentz.UStore.Haskell.GUStoreConversible GHC.Generics.U1
+ Lorentz.UStore.Haskell: instance Lorentz.UStore.Haskell.GUStoreConversible x => Lorentz.UStore.Haskell.GUStoreConversible (GHC.Generics.C1 i x)
+ Lorentz.UStore.Haskell: instance Lorentz.UStore.Haskell.GUStoreConversible x => Lorentz.UStore.Haskell.GUStoreConversible (GHC.Generics.D1 i x)
+ Lorentz.UStore.Haskell: instance Lorentz.UStore.Haskell.UStoreConversible template => Lorentz.UStore.Haskell.GUStoreConversible (GHC.Generics.S1 i (GHC.Generics.Rec0 template))
+ Lorentz.UStore.Haskell: migrateFillUStore :: (UStoreConversible template, allFieldsExp ~ AllUStoreFieldsF template, newDiff ~ FillingNewDiff template diff, newTouched ~ FillingNewTouched template touched, PatternMatchL newDiff, PatternMatchL newTouched) => template -> Lambda (MUStore oldTempl newTempl diff touched) (MUStore oldTempl newTempl newDiff newTouched)
+ Lorentz.UStore.Haskell: mkUStore :: UStoreConversible template => template -> UStore template
+ Lorentz.UStore.Haskell: type UStoreContent = [(ByteString, ByteString)]
+ Lorentz.UStore.Haskell: ustoreDecompose :: forall template. UStoreConversible template => UStore template -> Either Text (UStoreContent, template)
+ Lorentz.UStore.Haskell: ustoreDecomposeFull :: forall template. UStoreConversible template => UStore template -> Either Text template
+ Lorentz.UStore.Instances: instance Lorentz.UStore.Instr.HasUField fname ftype templ => Lorentz.StoreClass.StoreHasField (Lorentz.UStore.Types.UStore templ) fname ftype
+ Lorentz.UStore.Instances: instance Lorentz.UStore.Instr.HasUStore mname key value templ => Lorentz.StoreClass.StoreHasSubmap (Lorentz.UStore.Types.UStore templ) mname key value
+ Lorentz.UStore.Instr: instance GHC.Generics.Generic Lorentz.UStore.Instr.MyStoreTemplate
+ Lorentz.UStore.Instr: instance GHC.Generics.Generic Lorentz.UStore.Instr.MyStoreTemplate2
+ Lorentz.UStore.Instr: instance GHC.Generics.Generic Lorentz.UStore.Instr.MyStoreTemplate3
+ Lorentz.UStore.Instr: instance GHC.Generics.Generic Lorentz.UStore.Instr.MyStoreTemplateBig
+ Lorentz.UStore.Instr: instance Lorentz.UStore.Types.KnownUStoreMarker Lorentz.UStore.Instr.Marker1
+ Lorentz.UStore.Instr: instance Michelson.Typed.Haskell.Value.IsoCValue Lorentz.UStore.Instr.MyNatural
+ Lorentz.UStore.Instr: instance Michelson.Typed.Haskell.Value.IsoValue Lorentz.UStore.Instr.MyNatural
+ Lorentz.UStore.Instr: packSubMapUKey :: forall (field :: Symbol) k s. (KnownSymbol field, NicePackedValue k) => (k : s) :-> (ByteString : s)
+ Lorentz.UStore.Instr: type HasUField name ty store = (FieldAccessC store name, GetUStoreField store name ~ ty)
+ Lorentz.UStore.Instr: type HasUStore name key value store = (KeyAccessC store name, ValueAccessC store name, GetUStoreKey store name ~ key, GetUStoreValue store name ~ value)
+ Lorentz.UStore.Instr: type HasUStoreForAllIn store constrained = (Generic store, GHasStoreForAllIn constrained (Rep store))
+ Lorentz.UStore.Instr: unsafeEmptyUStore :: forall store s. s :-> (UStore store : s)
+ Lorentz.UStore.Instr: ustoreDelete :: forall store name s. KeyAccessC store name => Label name -> (GetUStoreKey store name : (UStore store : s)) :-> (UStore store : s)
+ Lorentz.UStore.Instr: ustoreGet :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (GetUStoreKey store name : (UStore store : s)) :-> (Maybe (GetUStoreValue store name) : s)
+ Lorentz.UStore.Instr: ustoreGetField :: forall store name s. FieldAccessC store name => Label name -> (UStore store : s) :-> (GetUStoreField store name : (UStore store : s))
+ Lorentz.UStore.Instr: ustoreInsert :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (GetUStoreKey store name : (GetUStoreValue store name : (UStore store : s))) :-> (UStore store : s)
+ Lorentz.UStore.Instr: ustoreInsertNew :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (forall s0 any. (GetUStoreKey store name : s0) :-> any) -> (GetUStoreKey store name : (GetUStoreValue store name : (UStore store : s))) :-> (UStore store : s)
+ Lorentz.UStore.Instr: ustoreMem :: forall store name s. KeyAccessC store name => Label name -> (GetUStoreKey store name : (UStore store : s)) :-> (Bool : s)
+ Lorentz.UStore.Instr: ustoreRemoveFieldUnsafe :: forall store name s. FieldAccessC store name => Label name -> (UStore store : s) :-> (UStore store : s)
+ Lorentz.UStore.Instr: ustoreSetField :: forall store name s. FieldAccessC store name => Label name -> (GetUStoreField store name : (UStore store : s)) :-> (UStore store : s)
+ Lorentz.UStore.Instr: ustoreToField :: forall store name s. FieldAccessC store name => Label name -> (UStore store : s) :-> (GetUStoreField store name : s)
+ Lorentz.UStore.Instr: ustoreUpdate :: forall store name s. (KeyAccessC store name, ValueAccessC store name) => Label name -> (GetUStoreKey store name : (Maybe (GetUStoreValue store name) : (UStore store : s))) :-> (UStore store : s)
+ Lorentz.UStore.Lift: instance GHC.Generics.Generic Lorentz.UStore.Lift.MyStoreTemplate
+ Lorentz.UStore.Lift: instance GHC.Generics.Generic Lorentz.UStore.Lift.MyStoreTemplateBig
+ Lorentz.UStore.Lift: liftUStore :: (Generic template, RequireAllUniqueFields template) => Label name -> (UStore (GetFieldType template name) : s) :-> (UStore template : s)
+ Lorentz.UStore.Lift: type UStoreFieldsAreUnique template = AllUnique (UStoreFields template)
+ Lorentz.UStore.Lift: unliftUStore :: Generic template => Label name -> (UStore template : s) :-> (UStore (GetFieldType template name) : s)
+ Lorentz.UStore.Migration.Base: DAddAction :: Text -> DMigrationActionType
+ Lorentz.UStore.Migration.Base: DDelAction :: DMigrationActionType
+ Lorentz.UStore.Migration.Base: DMigrationActionDesc :: DMigrationActionType -> Text -> T -> DMigrationActionDesc
+ Lorentz.UStore.Migration.Base: MUStoreUnsafe :: UStore oldTemplate -> MUStore
+ Lorentz.UStore.Migration.Base: MigrationAtom :: Text -> MigrationScript -> [DMigrationActionDesc] -> MigrationAtom
+ Lorentz.UStore.Migration.Base: MigrationBatching :: ([MigrationAtom] -> structure (batchInfo, MigrationScript)) -> MigrationBatching
+ Lorentz.UStore.Migration.Base: MigrationBlocks :: [MigrationAtom] -> MigrationBlocks
+ Lorentz.UStore.Migration.Base: MigrationScript :: Lambda UStore_ UStore_ -> MigrationScript
+ Lorentz.UStore.Migration.Base: UStoreMigrationCompiled :: structure (batchInfo, MigrationScript) -> UStoreMigrationCompiled
+ Lorentz.UStore.Migration.Base: [UStoreMigration] :: (oldStore ~ UStore oldTemplate, newStore ~ UStore newTemplate) => [MigrationAtom] -> UStoreMigration oldStore newStore
+ Lorentz.UStore.Migration.Base: [compiledMigrationContent] :: UStoreMigrationCompiled -> structure (batchInfo, MigrationScript)
+ Lorentz.UStore.Migration.Base: [maActionsDesc] :: MigrationAtom -> [DMigrationActionDesc]
+ Lorentz.UStore.Migration.Base: [maName] :: MigrationAtom -> Text
+ Lorentz.UStore.Migration.Base: [maScript] :: MigrationAtom -> MigrationScript
+ Lorentz.UStore.Migration.Base: [manAction] :: DMigrationActionDesc -> DMigrationActionType
+ Lorentz.UStore.Migration.Base: [manFieldType] :: DMigrationActionDesc -> T
+ Lorentz.UStore.Migration.Base: [manField] :: DMigrationActionDesc -> Text
+ Lorentz.UStore.Migration.Base: [unMigrationScript] :: MigrationScript -> Lambda UStore_ UStore_
+ Lorentz.UStore.Migration.Base: attachMigrationActionName :: (KnownSymbol fieldName, SingI (ToT fieldTy)) => DMigrationActionType -> Label fieldName -> Proxy fieldTy -> s :-> s
+ Lorentz.UStore.Migration.Base: buildMigrationPlan :: (Traversable t, Buildable batchInfo) => UStoreMigrationCompiled t batchInfo -> Builder
+ Lorentz.UStore.Migration.Base: compileMigration :: MigrationBatching t batchInfo -> UStoreMigration ot nt -> UStoreMigrationCompiled t batchInfo
+ Lorentz.UStore.Migration.Base: data DMigrationActionDesc
+ Lorentz.UStore.Migration.Base: data DMigrationActionType
+ Lorentz.UStore.Migration.Base: data MigrationAtom
+ Lorentz.UStore.Migration.Base: data MigrationBatching (structure :: Type -> Type) (batchInfo :: Type)
+ Lorentz.UStore.Migration.Base: data SomeUTemplate
+ Lorentz.UStore.Migration.Base: data UStoreMigration (oldStore :: Type) (newStore :: Type)
+ Lorentz.UStore.Migration.Base: formMigrationAtom :: Maybe Text -> Lambda UStore_ UStore_ -> MigrationAtom
+ Lorentz.UStore.Migration.Base: fromUStore_ :: UStore_ -> UStore template
+ Lorentz.UStore.Migration.Base: instance Control.Lens.Wrapped.Wrapped Lorentz.UStore.Migration.Base.MigrationScript
+ Lorentz.UStore.Migration.Base: instance Formatting.Buildable.Buildable Lorentz.UStore.Migration.Base.DMigrationActionType
+ Lorentz.UStore.Migration.Base: instance GHC.Generics.Generic (Lorentz.UStore.Migration.Base.MUStore oldTemplate newTemplate remDiff touched)
+ Lorentz.UStore.Migration.Base: instance GHC.Generics.Generic Lorentz.UStore.Migration.Base.MigrationScript
+ Lorentz.UStore.Migration.Base: instance GHC.Show.Show Lorentz.UStore.Migration.Base.DMigrationActionDesc
+ Lorentz.UStore.Migration.Base: instance GHC.Show.Show Lorentz.UStore.Migration.Base.DMigrationActionType
+ Lorentz.UStore.Migration.Base: instance GHC.Show.Show Lorentz.UStore.Migration.Base.MigrationAtom
+ Lorentz.UStore.Migration.Base: instance GHC.Show.Show Lorentz.UStore.Migration.Base.MigrationScript
+ Lorentz.UStore.Migration.Base: instance Michelson.Doc.DocItem Lorentz.UStore.Migration.Base.DMigrationActionDesc
+ Lorentz.UStore.Migration.Base: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Lorentz.UStore.Migration.Base.MigrationScript
+ Lorentz.UStore.Migration.Base: instance Michelson.Typed.Haskell.Value.IsoValue (Lorentz.UStore.Migration.Base.MUStore oldTemplate newTemplate remDiff touched)
+ Lorentz.UStore.Migration.Base: instance Michelson.Typed.Haskell.Value.IsoValue Lorentz.UStore.Migration.Base.MigrationScript
+ Lorentz.UStore.Migration.Base: maActionsDescL :: Lens' MigrationAtom [DMigrationActionDesc]
+ Lorentz.UStore.Migration.Base: maNameL :: Lens' MigrationAtom Text
+ Lorentz.UStore.Migration.Base: maScriptL :: Lens' MigrationAtom MigrationScript
+ Lorentz.UStore.Migration.Base: manualConcatMigrationScripts :: [MigrationScript] -> MigrationScript
+ Lorentz.UStore.Migration.Base: manualWithUStore :: forall ustore template. ustore ~ UStore template => ('[ustore] :-> '[ustore]) -> MigrationScript
+ Lorentz.UStore.Migration.Base: mapMigrationCode :: (forall i o. (i :-> o) -> i :-> o) -> UStoreMigration os ns -> UStoreMigration os ns
+ Lorentz.UStore.Migration.Base: mbBatchesAsIs :: MigrationBatching [] Text
+ Lorentz.UStore.Migration.Base: mbNoBatching :: MigrationBatching Identity Text
+ Lorentz.UStore.Migration.Base: migrationStagesNum :: Traversable t => UStoreMigrationCompiled t batchInfo -> Int
+ Lorentz.UStore.Migration.Base: migrationToInfo :: Traversable t => UStoreMigrationCompiled t batchInfo -> t batchInfo
+ Lorentz.UStore.Migration.Base: migrationToLambda :: UStoreMigrationT oldTemplate newTemplate -> Lambda (UStore oldTemplate) (UStore newTemplate)
+ Lorentz.UStore.Migration.Base: migrationToScript :: UStoreMigration ot nt -> MigrationScript
+ Lorentz.UStore.Migration.Base: migrationToScripts :: Traversable t => UStoreMigrationCompiled t batchInfo -> t MigrationScript
+ Lorentz.UStore.Migration.Base: migrationToScriptsList :: Traversable t => UStoreMigrationCompiled t batchInfo -> [MigrationScript]
+ Lorentz.UStore.Migration.Base: mkUStoreBatchedMigration :: MigrationBlocks oldTempl newTempl (BuildDiff oldTempl newTempl) '[] '[] _1 -> UStoreMigrationT oldTempl newTempl
+ Lorentz.UStore.Migration.Base: mkUStoreMigration :: Lambda (MUStore oldTempl newTempl (BuildDiff oldTempl newTempl) '[]) (MUStore oldTempl newTempl '[] _1) -> UStoreMigrationT oldTempl newTempl
+ Lorentz.UStore.Migration.Base: newtype MUStore (oldTemplate :: Type) (newTemplate :: Type) (remDiff :: [DiffItem]) (touched :: [Symbol])
+ Lorentz.UStore.Migration.Base: newtype MigrationBlocks (oldTemplate :: Type) (newTemplate :: Type) (preRemDiff :: [DiffItem]) (preTouched :: [Symbol]) (postRemDiff :: [DiffItem]) (postTouched :: [Symbol])
+ Lorentz.UStore.Migration.Base: newtype MigrationScript
+ Lorentz.UStore.Migration.Base: newtype UStoreMigrationCompiled (structure :: Type -> Type) (batchInfo :: Type)
+ Lorentz.UStore.Migration.Base: toUStore_ :: UStore template -> UStore_
+ Lorentz.UStore.Migration.Base: type InitUStore = UStore ()
+ Lorentz.UStore.Migration.Base: type UStoreMigrationT ot nt = UStoreMigration (UStore ot) (UStore nt)
+ Lorentz.UStore.Migration.Base: type UStore_ = UStore SomeUTemplate
+ Lorentz.UStore.Migration.Batching: SlBatchInfo :: SlBatchType -> [Text] -> SlBatchInfo
+ Lorentz.UStore.Migration.Batching: SlbtCustom :: SlBatchType
+ Lorentz.UStore.Migration.Batching: SlbtData :: SlBatchType
+ Lorentz.UStore.Migration.Batching: SlbtLambda :: SlBatchType
+ Lorentz.UStore.Migration.Batching: SlbtUnknown :: SlBatchType
+ Lorentz.UStore.Migration.Batching: [slbiActions] :: SlBatchInfo -> [Text]
+ Lorentz.UStore.Migration.Batching: [slbiType] :: SlBatchInfo -> SlBatchType
+ Lorentz.UStore.Migration.Batching: data SlBatchInfo
+ Lorentz.UStore.Migration.Batching: data SlBatchType
+ Lorentz.UStore.Migration.Batching: instance Formatting.Buildable.Buildable Lorentz.UStore.Migration.Batching.SlBatchInfo
+ Lorentz.UStore.Migration.Batching: instance GHC.Classes.Eq Lorentz.UStore.Migration.Batching.SlBatchType
+ Lorentz.UStore.Migration.Batching: instance GHC.Show.Show Lorentz.UStore.Migration.Batching.SlBatchType
+ Lorentz.UStore.Migration.Batching: mbSeparateLambdas :: MigrationBatching [] SlBatchInfo
+ Lorentz.UStore.Migration.Blocks: ($:) :: (a -> b) -> a -> b
+ Lorentz.UStore.Migration.Blocks: (<-->) :: MigrationBlocks o n d1 t1 d2 t2 -> MigrationBlocks o n d2 t2 d3 t3 -> MigrationBlocks o n d1 t1 d3 t3
+ Lorentz.UStore.Migration.Blocks: class MigrationFinishCheckPosition a
+ Lorentz.UStore.Migration.Blocks: infixl 2 <-->
+ Lorentz.UStore.Migration.Blocks: infixr 7 $:
+ Lorentz.UStore.Migration.Blocks: instance (Lorentz.UStore.Migration.Diff.RequireEmptyDiff d1, t1 Data.Type.Equality.~ t2) => Lorentz.UStore.Migration.Blocks.MigrationFinishCheckPosition (Lorentz.UStore.Migration.Base.MigrationBlocks o n d1 t1 '[] t2)
+ Lorentz.UStore.Migration.Blocks: instance (i Data.Type.Equality.~ (Lorentz.UStore.Migration.Base.MUStore oldTempl newTempl diff touched : s), o Data.Type.Equality.~ (Lorentz.UStore.Migration.Base.MUStore oldTempl newTempl '[] touched : s), Lorentz.UStore.Migration.Diff.RequireEmptyDiff diff) => Lorentz.UStore.Migration.Blocks.MigrationFinishCheckPosition (i Lorentz.Base.:-> o)
+ Lorentz.UStore.Migration.Blocks: migrateAddField :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s. ('(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcAdd field diff, HasUField field fieldTy newTempl) => Label field -> (fieldTy : (MUStore oldTempl newTempl diff touched : s)) :-> (MUStore oldTempl newTempl newDiff (field : touched) : s)
+ Lorentz.UStore.Migration.Blocks: migrateCoerceUnsafe :: forall field oldTempl newTempl diff touched newDiff newDiff0 _1 _2 s. ('(_1, newDiff0) ~ CoverDiff 'DcRemove field diff, '(_2, newDiff) ~ CoverDiff 'DcAdd field newDiff0) => Label field -> (MUStore oldTempl newTempl diff touched : s) :-> (MUStore oldTempl newTempl newDiff touched : s)
+ Lorentz.UStore.Migration.Blocks: migrateExtractField :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s. ('(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcRemove field diff, HasUField field fieldTy oldTempl, RequireUntouched field (field `IsElem` touched)) => Label field -> (MUStore oldTempl newTempl diff touched : s) :-> (fieldTy : (MUStore oldTempl newTempl newDiff (field : touched) : s))
+ Lorentz.UStore.Migration.Blocks: migrateGetField :: forall field oldTempl newTempl diff touched fieldTy s. (HasUField field fieldTy oldTempl, RequireUntouched field (field `IsElem` touched)) => Label field -> (MUStore oldTempl newTempl diff touched : s) :-> (fieldTy : (MUStore oldTempl newTempl diff touched : s))
+ Lorentz.UStore.Migration.Blocks: migrateModifyField :: forall field oldTempl newTempl diff touched fieldTy s. (HasUField field fieldTy oldTempl, HasUField field fieldTy newTempl) => Label field -> (fieldTy : (MUStore oldTempl newTempl diff touched : s)) :-> (MUStore oldTempl newTempl diff touched : s)
+ Lorentz.UStore.Migration.Blocks: migrateOverwriteField :: forall field oldTempl newTempl diff touched fieldTy oldFieldTy marker oldMarker newDiff newDiff0 s. ('(UStoreFieldExt oldMarker oldFieldTy, newDiff0) ~ CoverDiff 'DcRemove field diff, '(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcAdd field newDiff0, HasUField field fieldTy newTempl) => Label field -> (fieldTy : (MUStore oldTempl newTempl diff touched : s)) :-> (MUStore oldTempl newTempl newDiff (field : touched) : s)
+ Lorentz.UStore.Migration.Blocks: migrateRemoveField :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s. ('(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcRemove field diff, HasUField field fieldTy oldTempl) => Label field -> (MUStore oldTempl newTempl diff touched : s) :-> (MUStore oldTempl newTempl newDiff (field : touched) : s)
+ Lorentz.UStore.Migration.Blocks: migrationFinish :: MigrationFinishCheckPosition a => a
+ Lorentz.UStore.Migration.Blocks: muBlock :: ('[MUStore o n d1 t1] :-> '[MUStore o n d2 t2]) -> MigrationBlocks o n d1 t1 d2 t2
+ Lorentz.UStore.Migration.Blocks: muBlockNamed :: Text -> ('[MUStore o n d1 t1] :-> '[MUStore o n d2 t2]) -> MigrationBlocks o n d1 t1 d2 t2
+ Lorentz.UStore.Migration.Blocks: mustoreToOld :: RequireBeInitial touched => (MUStore oldTemplate newTemplate remDiff touched : s) :-> (UStore oldTemplate : s)
+ Lorentz.UStore.Migration.Diff: DcAdd :: DiffCoverage
+ Lorentz.UStore.Migration.Diff: DcRemove :: DiffCoverage
+ Lorentz.UStore.Migration.Diff: ToAdd :: DiffKind
+ Lorentz.UStore.Migration.Diff: ToDel :: DiffKind
+ Lorentz.UStore.Migration.Diff: data DiffCoverage
+ Lorentz.UStore.Migration.Diff: data DiffKind
+ Lorentz.UStore.Migration.Diff: data LinearizeUStoreF (template :: Type) :: Exp [FieldInfo]
+ Lorentz.UStore.Migration.Diff: type BuildDiff oldTemplate newTemplate = LiftToDiff 'ToAdd (LinearizeUStore newTemplate // LinearizeUStore oldTemplate) ++ LiftToDiff 'ToDel (LinearizeUStore oldTemplate // LinearizeUStore newTemplate)
+ Lorentz.UStore.Migration.Diff: type DiffItem = (DiffKind, FieldInfo)
+ Lorentz.UStore.Migration.Diff: type FieldInfo = (Symbol, Type)
+ Lorentz.UStore.Migration.Diff: type LinearizeUStore a = GLinearizeUStore (Rep a)
+ Lorentz.UStore.Migration.Diff: type ShowDiff diff = 'Text "Migration is incomplete, remaining diff:" :$$: ShowDiffItems diff
+ Lorentz.UStore.Migration.Diff: type family CoverDiffMany (diff :: [DiffItem]) (covers :: [DiffCoverageItem]) :: [DiffItem]
+ Lorentz.UStore.Types: -- and field value type. Used for error messages.
+ Lorentz.UStore.Types: -- | Display type-level information about UStore field with given marker
+ Lorentz.UStore.Types: FieldSignature :: UStoreMarkerType -> Type -> ElemSignature
+ Lorentz.UStore.Types: MapSignature :: Type -> Type -> ElemSignature
+ Lorentz.UStore.Types: UStore :: BigMap ByteString ByteString -> UStore
+ Lorentz.UStore.Types: UStoreField :: v -> UStoreFieldExt
+ Lorentz.UStore.Types: UStoreSubMap :: Map k v -> (|~>) k v
+ Lorentz.UStore.Types: [unUStoreField] :: UStoreFieldExt -> v
+ Lorentz.UStore.Types: [unUStoreSubMap] :: (|~>) k v -> Map k v
+ Lorentz.UStore.Types: [unUStore] :: UStore -> BigMap ByteString ByteString
+ Lorentz.UStore.Types: class KnownUStoreMarker (marker :: UStoreMarkerType) where {
+ Lorentz.UStore.Types: data ElemSignature
+ Lorentz.UStore.Types: data UMarkerPlainField :: UStoreMarkerType
+ Lorentz.UStore.Types: instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (k Lorentz.UStore.Types.|~> v)
+ Lorentz.UStore.Types: instance (GHC.Show.Show k, GHC.Show.Show v) => GHC.Show.Show (k Lorentz.UStore.Types.|~> v)
+ Lorentz.UStore.Types: instance Data.Default.Class.Default (Lorentz.UStore.Types.UStore a)
+ Lorentz.UStore.Types: instance Data.Default.Class.Default (k Lorentz.UStore.Types.|~> v)
+ Lorentz.UStore.Types: instance Data.Typeable.Internal.Typeable template => Michelson.Typed.Haskell.Doc.TypeHasDoc (Lorentz.UStore.Types.UStore template)
+ Lorentz.UStore.Types: instance GHC.Base.Monoid (Lorentz.UStore.Types.UStore a)
+ Lorentz.UStore.Types: instance GHC.Base.Semigroup (Lorentz.UStore.Types.UStore a)
+ Lorentz.UStore.Types: instance GHC.Classes.Eq (Lorentz.UStore.Types.UStore a)
+ Lorentz.UStore.Types: instance GHC.Classes.Eq v => GHC.Classes.Eq (Lorentz.UStore.Types.UStoreFieldExt m v)
+ Lorentz.UStore.Types: instance GHC.Generics.Generic (Lorentz.UStore.Types.UStore a)
+ Lorentz.UStore.Types: instance GHC.Show.Show (Lorentz.UStore.Types.UStore a)
+ Lorentz.UStore.Types: instance GHC.Show.Show v => GHC.Show.Show (Lorentz.UStore.Types.UStoreFieldExt m v)
+ Lorentz.UStore.Types: instance Lorentz.Polymorphic.GetOpHs (Lorentz.UStore.Types.UStore a)
+ Lorentz.UStore.Types: instance Lorentz.Polymorphic.MemOpHs (Lorentz.UStore.Types.UStore a)
+ Lorentz.UStore.Types: instance Lorentz.Polymorphic.UpdOpHs (Lorentz.UStore.Types.UStore a)
+ Lorentz.UStore.Types: instance Lorentz.UStore.Types.KnownUStoreMarker Lorentz.UStore.Types.UMarkerPlainField
+ Lorentz.UStore.Types: instance Michelson.Typed.Haskell.Value.IsoValue (Lorentz.UStore.Types.UStore a)
+ Lorentz.UStore.Types: mkFieldMarkerUKey :: (KnownUStoreMarker marker, KnownSymbol name) => Label name -> ByteString
+ Lorentz.UStore.Types: mkFieldUKey :: forall (store :: Type) name. (KnownSymbol name, KnownUStoreMarker (GetUStoreFieldMarker store name)) => Label name -> ByteString
+ Lorentz.UStore.Types: newtype UStore (a :: Type)
+ Lorentz.UStore.Types: newtype UStoreFieldExt (m :: UStoreMarkerType) (v :: Type)
+ Lorentz.UStore.Types: newtype k |~> v
+ Lorentz.UStore.Types: type GetUStore name a = MERequireFound name a (GLookupStore name (Rep a))
+ Lorentz.UStore.Types: type GetUStoreField store name = FSValue (GetUStore name store)
+ Lorentz.UStore.Types: type GetUStoreFieldMarker store name = FSMarker (GetUStore name store)
+ Lorentz.UStore.Types: type GetUStoreKey store name = MSKey (GetUStore name store)
+ Lorentz.UStore.Types: type GetUStoreValue store name = MSValue (GetUStore name store)
+ Lorentz.UStore.Types: type PickMarkedFields marker template = GPickMarkedFields marker (Rep template)
+ Lorentz.UStore.Types: type ShowUStoreField marker v = 'Text "field of type " :<>: 'ShowType v;
+ Lorentz.UStore.Types: type UStoreField = UStoreFieldExt UMarkerPlainField
+ Lorentz.UStore.Types: type UStoreMarkerType = UStoreMarker -> Type
+ Lorentz.UStore.Types: type family FSMarker (ms :: ElemSignature) :: UStoreMarkerType
+ Lorentz.UStore.Types: }
+ Lorentz.Value: ContractRef :: Address -> SomeEntryPointCall arg -> ContractRef
+ Lorentz.Value: EpAddress :: Address -> EpName -> EpAddress
+ Lorentz.Value: FutureContract :: EpAddress -> FutureContract p
+ Lorentz.Value: [crAddress] :: ContractRef -> Address
+ Lorentz.Value: [crEntryPoint] :: ContractRef -> SomeEntryPointCall arg
+ Lorentz.Value: [eaAddress] :: EpAddress -> Address
+ Lorentz.Value: [eaEntryPoint] :: EpAddress -> EpName
+ Lorentz.Value: [futureContractAddress] :: FutureContract p -> EpAddress
+ Lorentz.Value: class FromContractRef (cp :: Type) (contract :: Type)
+ Lorentz.Value: class ToAddress a
+ Lorentz.Value: class ToContractRef (cp :: Type) (contract :: Type)
+ Lorentz.Value: coerceContractRef :: ToT a ~ ToT b => ContractRef a -> ContractRef b
+ Lorentz.Value: convertContractRef :: forall cp contract2 contract1. (ToContractRef cp contract1, FromContractRef cp contract2) => contract1 -> contract2
+ Lorentz.Value: data ChainId
+ Lorentz.Value: data ContractRef (arg :: Type)
+ Lorentz.Value: data EpAddress
+ Lorentz.Value: embodyFutureContract :: forall arg. (NiceParameter arg, HasCallStack) => FutureContract arg -> ContractRef arg
+ Lorentz.Value: fromContractAddr :: FromContractRef cp contract => ContractRef cp -> contract
+ Lorentz.Value: instance (Lorentz.Constraints.NiceParameter cp, cp Data.Type.Equality.~ cp') => Lorentz.Value.ToContractRef cp (Lorentz.Value.FutureContract cp')
+ Lorentz.Value: instance (cp Data.Type.Equality.~ cp') => Lorentz.Value.FromContractRef cp (Lorentz.Value.FutureContract cp')
+ Lorentz.Value: instance (cp Data.Type.Equality.~ cp') => Lorentz.Value.FromContractRef cp (Michelson.Typed.Haskell.Value.ContractRef cp')
+ Lorentz.Value: instance (cp Data.Type.Equality.~ cp') => Lorentz.Value.ToContractRef cp (Michelson.Typed.Haskell.Value.ContractRef cp')
+ Lorentz.Value: instance Lorentz.Constraints.NiceParameter cp => Lorentz.Value.ToContractRef cp Michelson.Typed.EntryPoints.EpAddress
+ Lorentz.Value: instance Lorentz.Constraints.NiceParameter cp => Lorentz.Value.ToContractRef cp Tezos.Address.Address
+ Lorentz.Value: instance Lorentz.Value.FromContractRef cp Michelson.Typed.EntryPoints.EpAddress
+ Lorentz.Value: instance Lorentz.Value.FromContractRef cp Tezos.Address.Address
+ Lorentz.Value: instance Lorentz.Value.ToAddress (Michelson.Typed.Haskell.Value.ContractRef cp)
+ Lorentz.Value: instance Lorentz.Value.ToAddress Michelson.Typed.EntryPoints.EpAddress
+ Lorentz.Value: instance Lorentz.Value.ToAddress Tezos.Address.Address
+ Lorentz.Value: instance forall k (cp :: k). Lorentz.Value.ToAddress (Lorentz.Value.FutureContract cp)
+ Lorentz.Value: instance forall k (p :: k). GHC.Generics.Generic (Lorentz.Value.FutureContract p)
+ Lorentz.Value: instance forall k (p :: k). Michelson.Typed.Haskell.Value.IsoValue (Lorentz.Value.FutureContract p)
+ Lorentz.Value: newtype FutureContract p
+ Lorentz.Value: timestampFromSeconds :: Integer -> Timestamp
+ Lorentz.Value: timestampFromUTCTime :: UTCTime -> Timestamp
+ Lorentz.Value: timestampQuote :: QuasiQuoter
+ Lorentz.Value: toAddress :: ToAddress a => a -> Address
+ Lorentz.Value: toContractRef :: (ToContractRef cp contract, HasCallStack) => contract -> ContractRef cp
+ Lorentz.Value: type EntryPointCall param arg = EntryPointCallT (ToT param) (ToT arg)
+ Lorentz.Value: type SomeEntryPointCall arg = SomeEntryPointCallT (ToT arg)
+ Lorentz.Zip: -- | A type which contains the whole stack zipped.
+ Lorentz.Zip: class ZipInstr (s :: [Type]) where {
+ Lorentz.Zip: instance (Lorentz.Zip.ZipInstr inp, Lorentz.Zip.ZipInstr out) => Michelson.Typed.Haskell.Value.IsoValue (inp Lorentz.Base.:-> out)
+ Lorentz.Zip: instance Lorentz.Zip.ZipInstr '[]
+ Lorentz.Zip: instance Lorentz.Zip.ZipInstr '[a]
+ Lorentz.Zip: instance Lorentz.Zip.ZipInstr ((a, b) : s) => Lorentz.Zip.ZipInstr (a : b : s)
+ Lorentz.Zip: type ZipInstrs ss = Each '[ZipInstr] ss
+ Lorentz.Zip: type family ZippedStack s :: Type;
+ Lorentz.Zip: unzipInstr :: ZipInstr s => '[ZippedStack s] :-> s
+ Lorentz.Zip: unzippingStack :: ZipInstrs [inp, out] => Lambda (ZippedStack inp) (ZippedStack out) -> inp :-> out
+ Lorentz.Zip: zipInstr :: ZipInstr s => s :-> '[ZippedStack s]
+ Lorentz.Zip: zippingStack :: ZipInstrs [inp, out] => (inp :-> out) -> Lambda (ZippedStack inp) (ZippedStack out)
+ Lorentz.Zip: }
+ Michelson.Analyzer: AnalyzerRes :: !HashMap MText Word -> !HashMap ByteString Word -> !HashMap MText Word -> AnalyzerRes
+ Michelson.Analyzer: [arConstBytes] :: AnalyzerRes -> !HashMap ByteString Word
+ Michelson.Analyzer: [arConstStrings] :: AnalyzerRes -> !HashMap MText Word
+ Michelson.Analyzer: [arErrorTags] :: AnalyzerRes -> !HashMap MText Word
+ Michelson.Analyzer: analyze :: Instr inp out -> AnalyzerRes
+ Michelson.Analyzer: data AnalyzerRes
+ Michelson.Analyzer: instance Formatting.Buildable.Buildable Michelson.Analyzer.AnalyzerRes
+ Michelson.Analyzer: instance GHC.Base.Monoid Michelson.Analyzer.AnalyzerRes
+ Michelson.Analyzer: instance GHC.Base.Semigroup Michelson.Analyzer.AnalyzerRes
+ Michelson.Analyzer: instance GHC.Classes.Eq Michelson.Analyzer.AnalyzerRes
+ Michelson.Analyzer: instance GHC.Show.Show Michelson.Analyzer.AnalyzerRes
+ Michelson.Doc: --
+ Michelson.Doc: -- Documentation structure is not necessarily flat. If some doc item
+ Michelson.Doc: -- Inline right here (default behaviour); 2. Put into definitions
+ Michelson.Doc: -- Note that we require all doc items with "in definitions" placement to
+ Michelson.Doc: -- consolidates a whole documentation block within it, this block will
+ Michelson.Doc: -- doc.
+ Michelson.Doc: -- have <a>Eq</a> and <a>Ord</a> instances which comply the following
+ Michelson.Doc: -- law: if two documentation items describe the same entity or property,
+ Michelson.Doc: -- section.
+ Michelson.Doc: -- they should be considered equal.
+ Michelson.Doc: -- value, the higher the section with this element will be placed.
+ Michelson.Doc: -- | Defines where given doc item should be put. There are two options: 1.
+ Michelson.Doc: ContractDoc :: DocBlock -> DocBlock -> Set SomeDocDefinitionItem -> Set DocItemId -> ContractDoc
+ Michelson.Doc: DComment :: Text -> DComment
+ Michelson.Doc: DDescription :: Markdown -> DDescription
+ Michelson.Doc: DGitRevision :: GitRepoSettings -> Text -> Text -> DGitRevision
+ Michelson.Doc: DName :: Text -> SubDoc -> DName
+ Michelson.Doc: DVersion :: Natural -> DVersion
+ Michelson.Doc: DocItemId :: Text -> DocItemId
+ Michelson.Doc: DocItemInDefinitions :: DocItemPlacementKind
+ Michelson.Doc: DocItemInlined :: DocItemPlacementKind
+ Michelson.Doc: DocSectionNameBig :: DocSectionNameStyle
+ Michelson.Doc: DocSectionNameSmall :: DocSectionNameStyle
+ Michelson.Doc: GitRepoSettings :: (Text -> Text) -> GitRepoSettings
+ Michelson.Doc: SubDoc :: DocBlock -> SubDoc
+ Michelson.Doc: [DocItemNoRef] :: DocItemRef 'DocItemInlined
+ Michelson.Doc: [DocItemRef] :: DocItemId -> DocItemRef 'DocItemInDefinitions
+ Michelson.Doc: [SomeDocDefinitionItem] :: (DocItem d, DocItemPlacement d ~ 'DocItemInDefinitions) => d -> SomeDocDefinitionItem
+ Michelson.Doc: [SomeDocItem] :: DocItem d => d -> SomeDocItem
+ Michelson.Doc: [cdContents] :: ContractDoc -> DocBlock
+ Michelson.Doc: [cdDefinitionIds] :: ContractDoc -> Set DocItemId
+ Michelson.Doc: [cdDefinitionsSet] :: ContractDoc -> Set SomeDocDefinitionItem
+ Michelson.Doc: [cdDefinitions] :: ContractDoc -> DocBlock
+ Michelson.Doc: [dgrCommitDate] :: DGitRevision -> Text
+ Michelson.Doc: [dgrCommitSha] :: DGitRevision -> Text
+ Michelson.Doc: [dgrRepoSettings] :: DGitRevision -> GitRepoSettings
+ Michelson.Doc: [grsMkGitRevision] :: GitRepoSettings -> Text -> Text
+ Michelson.Doc: cdContentsL :: Lens' ContractDoc DocBlock
+ Michelson.Doc: cdDefinitionIdsL :: Lens' ContractDoc (Set DocItemId)
+ Michelson.Doc: cdDefinitionsL :: Lens' ContractDoc DocBlock
+ Michelson.Doc: cdDefinitionsSetL :: Lens' ContractDoc (Set SomeDocDefinitionItem)
+ Michelson.Doc: class (Typeable d, DOrd d, KnownNat (DocItemPosition d)) => DocItem d where {
+ Michelson.Doc: contractDocToMarkdown :: ContractDoc -> LText
+ Michelson.Doc: data ContractDoc
+ Michelson.Doc: data DComment
+ Michelson.Doc: data DDescription
+ Michelson.Doc: data DGitRevision
+ Michelson.Doc: data DName
+ Michelson.Doc: data DVersion
+ Michelson.Doc: data DocItemPlacementKind
+ Michelson.Doc: data DocItemRef (p :: DocItemPlacementKind)
+ Michelson.Doc: data DocSectionNameStyle
+ Michelson.Doc: data SomeDocDefinitionItem
+ Michelson.Doc: data SomeDocItem
+ Michelson.Doc: docDefinitionRef :: (DocItem d, DocItemPlacement d ~ 'DocItemInDefinitions) => Markdown -> d -> Markdown
+ Michelson.Doc: docGroupContent :: DocGrouping -> ContractDoc -> ContractDoc
+ Michelson.Doc: docItemDependencies :: DocItem d => d -> [SomeDocDefinitionItem]
+ Michelson.Doc: docItemPosition :: forall d. DocItem d => DocItemPos
+ Michelson.Doc: docItemRef :: (DocItem d, DocItemPlacement d ~ 'DocItemInlined) => d -> DocItemRef (DocItemPlacement d)
+ Michelson.Doc: docItemSectionDescription :: DocItem d => Maybe Markdown
+ Michelson.Doc: docItemSectionName :: DocItem d => Maybe Text
+ Michelson.Doc: docItemSectionNameStyle :: DocItem d => DocSectionNameStyle
+ Michelson.Doc: docItemToMarkdown :: DocItem d => HeaderLevel -> d -> Markdown
+ Michelson.Doc: docItemsOrder :: DocItem d => [d] -> [d]
+ Michelson.Doc: instance Formatting.Buildable.Buildable Michelson.Doc.DocItemPos
+ Michelson.Doc: instance GHC.Base.Monoid Michelson.Doc.ContractDoc
+ Michelson.Doc: instance GHC.Base.Semigroup Michelson.Doc.ContractDoc
+ Michelson.Doc: instance GHC.Classes.Eq Michelson.Doc.DocItemId
+ Michelson.Doc: instance GHC.Classes.Eq Michelson.Doc.DocItemPos
+ Michelson.Doc: instance GHC.Classes.Eq Michelson.Doc.SomeDocDefinitionItem
+ Michelson.Doc: instance GHC.Classes.Ord Michelson.Doc.DocItemId
+ Michelson.Doc: instance GHC.Classes.Ord Michelson.Doc.DocItemPos
+ Michelson.Doc: instance GHC.Classes.Ord Michelson.Doc.SomeDocDefinitionItem
+ Michelson.Doc: instance GHC.Show.Show Michelson.Doc.DocGrouping
+ Michelson.Doc: instance GHC.Show.Show Michelson.Doc.DocItemId
+ Michelson.Doc: instance GHC.Show.Show Michelson.Doc.DocItemPos
+ Michelson.Doc: instance GHC.Show.Show Michelson.Doc.SomeDocItem
+ Michelson.Doc: instance Michelson.Doc.DocItem Michelson.Doc.DComment
+ Michelson.Doc: instance Michelson.Doc.DocItem Michelson.Doc.DDescription
+ Michelson.Doc: instance Michelson.Doc.DocItem Michelson.Doc.DGitRevision
+ Michelson.Doc: instance Michelson.Doc.DocItem Michelson.Doc.DName
+ Michelson.Doc: instance Michelson.Doc.DocItem Michelson.Doc.DVersion
+ Michelson.Doc: mkDGitRevision :: Q Exp
+ Michelson.Doc: morleyRepoSettings :: GitRepoSettings
+ Michelson.Doc: newtype DocItemId
+ Michelson.Doc: newtype GitRepoSettings
+ Michelson.Doc: newtype SubDoc
+ Michelson.Doc: someDocItemToBlock :: SomeDocItem -> DocBlock
+ Michelson.Doc: subDocToMarkdown :: HeaderLevel -> SubDoc -> Markdown
+ Michelson.Doc: type DocBlock = Map DocItemPos (NonEmpty SomeDocItem)
+ Michelson.Doc: type DocGrouping = SubDoc -> SomeDocItem
+ Michelson.Doc: type DocItemPlacement d = 'DocItemInlined;
+ Michelson.Doc: type family DocItemPlacement d :: DocItemPlacementKind;
+ Michelson.Doc: }
+ Michelson.FailPattern: data TypicalFailWith
+ Michelson.FailPattern: instance (Data.Typeable.Internal.Typeable a, Michelson.Typed.Scope.ConstantScope a) => Michelson.FailPattern.ConstantScope' a
+ Michelson.FailPattern: isTypicalFailWith :: Instr inp out -> Maybe TypicalFailWith
+ Michelson.FailPattern: modifyTypicalFailWith :: (HasCallStack, ConstantScope t, Typeable t) => (MText -> Value t) -> Instr inp out -> Instr inp out
+ Michelson.FailPattern: typicalFailWithTag :: TypicalFailWith -> MText
+ Michelson.Interpret: [InterpretResult] :: StorageScope st => {iurOps :: [Operation], iurNewStorage :: Value st, iurNewState :: InterpreterState} -> InterpretResult
+ Michelson.Interpret: [MichelsonAmbigousEpRef] :: EpName -> EpAddress -> MichelsonFailed
+ Michelson.Interpret: [ceChainId] :: ContractEnv -> !ChainId
+ Michelson.Interpret: data InterpretError
+ Michelson.Interpret: data InterpretResult
+ Michelson.Interpret: instance Formatting.Buildable.Buildable Michelson.Interpret.InterpretError
+ Michelson.Interpret: instance GHC.Generics.Generic Michelson.Interpret.InterpretError
+ Michelson.Interpret: instance GHC.Show.Show Michelson.Interpret.InterpretError
+ Michelson.Interpret: instance GHC.Show.Show Michelson.Interpret.InterpretResult
+ Michelson.Interpret: interpretInstr :: ContractEnv -> Instr inp out -> Rec Value inp -> Either MichelsonFailed (Rec Value out)
+ Michelson.Interpret: interpretSome :: SomeContract -> SomeValue -> SomeValue -> ContractEnv -> Either InterpretError InterpretResult
+ Michelson.Interpret.Pack: encodeIntPayload :: Integer -> LByteString
+ Michelson.Interpret.Pack: packCode' :: Instr inp out -> ByteString
+ Michelson.Interpret.Pack: packT' :: forall (t :: T). SingI t => ByteString
+ Michelson.Interpret.Unpack: instance GHC.Exception.Type.Exception Michelson.Interpret.Unpack.UnpackError
+ Michelson.Macro: ACCESS :: Natural -> Positive -> Macro
+ Michelson.Macro: CONSTRUCT :: NonEmpty [ParsedOp] -> Macro
+ Michelson.Macro: SET :: Natural -> Positive -> Macro
+ Michelson.OpSize: OpSize :: Word -> OpSize
+ Michelson.OpSize: [unOpSize] :: OpSize -> Word
+ Michelson.OpSize: expandedInstrsOpSize :: [ExpandedOp] -> OpSize
+ Michelson.OpSize: instance GHC.Base.Monoid Michelson.OpSize.OpSize
+ Michelson.OpSize: instance GHC.Base.Semigroup Michelson.OpSize.OpSize
+ Michelson.OpSize: instance GHC.Classes.Eq Michelson.OpSize.OpSize
+ Michelson.OpSize: instance GHC.Classes.Ord Michelson.OpSize.OpSize
+ Michelson.OpSize: instance GHC.Show.Show Michelson.OpSize.OpSize
+ Michelson.OpSize: instance Michelson.OpSize.AnnsOpSizeVararg Michelson.OpSize.OpSize
+ Michelson.OpSize: instance forall k x (t :: k). Michelson.OpSize.AnnsOpSizeVararg x => Michelson.OpSize.AnnsOpSizeVararg (Michelson.Untyped.Annotation.Annotation t -> x)
+ Michelson.OpSize: instance forall k x (t :: k). Michelson.OpSize.AnnsOpSizeVararg x => Michelson.OpSize.AnnsOpSizeVararg ([Michelson.Untyped.Annotation.Annotation t] -> x)
+ Michelson.OpSize: instrOpSize :: InstrAbstract ExpandedOp -> OpSize
+ Michelson.OpSize: newtype OpSize
+ Michelson.OpSize: opSizeHardLimit :: OpSize
+ Michelson.OpSize: smallTransferOpSize :: OpSize
+ Michelson.OpSize: valueOpSize :: Value -> OpSize
+ Michelson.Optimizer: OptimizerConf :: Bool -> (Rule -> Rule) -> OptimizerConf
+ Michelson.Optimizer: [gotoValues] :: OptimizerConf -> Bool
+ Michelson.Optimizer: [ruleset] :: OptimizerConf -> Rule -> Rule
+ Michelson.Optimizer: data OptimizerConf
+ Michelson.Optimizer: defaultRules :: Rule -> Rule
+ Michelson.Optimizer: defaultRulesAndPushPack :: Rule -> Rule
+ Michelson.Optimizer: instance Data.Default.Class.Default Michelson.Optimizer.OptimizerConf
+ Michelson.Optimizer: optimize :: Instr inp out -> Instr inp out
+ Michelson.Optimizer: optimizeWithConf :: OptimizerConf -> Instr inp out -> Instr inp out
+ Michelson.Optimizer: orRule :: (Rule -> Rule) -> (Rule -> Rule) -> Rule -> Rule
+ Michelson.Optimizer: orSimpleRule :: (Rule -> Rule) -> Rule -> Rule -> Rule
+ Michelson.Optimizer: type Rule = forall inp out. Instr inp out -> Maybe (Instr inp out)
+ Michelson.Parser: WrongAccessArgs :: Natural -> Positive -> CustomParserException
+ Michelson.Parser: WrongSetArgs :: Natural -> Positive -> CustomParserException
+ Michelson.Parser: WrongTagArgs :: Natural -> Positive -> CustomParserException
+ Michelson.Parser: parseExpandValue :: Text -> Either ParserException Value
+ Michelson.Parser: parseValue :: Text -> Either ParserException ParsedValue
+ Michelson.Parser.Error: WrongAccessArgs :: Natural -> Positive -> CustomParserException
+ Michelson.Parser.Error: WrongSetArgs :: Natural -> Positive -> CustomParserException
+ Michelson.Parser.Error: WrongTagArgs :: Natural -> Positive -> CustomParserException
+ Michelson.Parser.Helpers: mparens :: Parser a -> Parser a
+ Michelson.Parser.Helpers: positive :: Parser Positive
+ Michelson.Preprocess: transformBytes :: Bool -> (ByteString -> ByteString) -> Instr inp out -> Instr inp out
+ Michelson.Preprocess: transformStrings :: Bool -> (MText -> MText) -> Instr inp out -> Instr inp out
+ Michelson.Printer: printSomeContract :: Bool -> SomeContract -> Text
+ Michelson.Printer: printTypedFullContract :: Bool -> FullContract p s -> Text
+ Michelson.Printer: printTypedValue :: forall t. ProperPrintedValBetterErrors t => Bool -> Value t -> Text
+ Michelson.Printer.Util: Prettier :: a -> Prettier a
+ Michelson.Printer.Util: addParens :: RenderContext -> Doc -> Doc
+ Michelson.Printer.Util: assertParensNotNeeded :: HasCallStack => RenderContext -> a -> a
+ Michelson.Printer.Util: data RenderContext
+ Michelson.Printer.Util: doesntNeedParens :: RenderContext
+ Michelson.Printer.Util: needsParens :: RenderContext
+ Michelson.Printer.Util: newtype Prettier a
+ Michelson.Runtime: IEIllTypedParameter :: !TCError -> InterpreterError' a
+ Michelson.Runtime: IEIllTypedStorage :: !TCError -> InterpreterError' a
+ Michelson.Runtime: IEZeroTransaction :: !a -> InterpreterError' a
+ Michelson.Runtime: [csTypedContract] :: ContractState -> !Maybe SomeContract
+ Michelson.Runtime: [csTypedStorage] :: ContractState -> !Maybe SomeValue
+ Michelson.Runtime.GState: [csTypedContract] :: ContractState -> !Maybe SomeContract
+ Michelson.Runtime.GState: [csTypedStorage] :: ContractState -> !Maybe SomeValue
+ Michelson.Runtime.GState: [gsChainId] :: GState -> ChainId
+ Michelson.Runtime.GState: getTypedContract :: GState -> ContractState -> Either TCError SomeContract
+ Michelson.Runtime.GState: getTypedStorage :: GState -> ContractState -> Either TCError SomeValue
+ Michelson.Runtime.GState: gsAddressesL :: Lens' GState (Map Address AddressState)
+ Michelson.Runtime.GState: gsChainIdL :: Lens' GState ChainId
+ Michelson.Test: (?-) :: Text -> a -> (Text, a)
+ Michelson.Test: branchout :: HasCallStack => [(Text, IntegrationalScenario)] -> IntegrationalScenario
+ Michelson.Test: concatTestTrees :: [IO [TestTree]] -> IO [TestTree]
+ Michelson.Test: expectNoStorageUpdates :: SuccessValidator
+ Michelson.Test: expectNoUpdates :: SuccessValidator
+ Michelson.Test: infixr 0 ?-
+ Michelson.Test: testTreesWithContract :: (Each [Typeable, SingI] [cp, st], HasCallStack) => FilePath -> ((Contract, Contract cp st) -> IO [TestTree]) -> IO [TestTree]
+ Michelson.Test: testTreesWithContractL :: (Each [Typeable, SingI] [ToT cp, ToT st], HasCallStack) => FilePath -> ((Contract, Contract cp st) -> IO [TestTree]) -> IO [TestTree]
+ Michelson.Test: testTreesWithTypedContract :: (Each [Typeable, SingI] [cp, st], HasCallStack) => FilePath -> (Contract cp st -> IO [TestTree]) -> IO [TestTree]
+ Michelson.Test: testTreesWithUntypedContract :: HasCallStack => FilePath -> (Contract -> IO [TestTree]) -> IO [TestTree]
+ Michelson.Test.Import: concatTestTrees :: [IO [TestTree]] -> IO [TestTree]
+ Michelson.Test.Import: testTreesWithContract :: (Each [Typeable, SingI] [cp, st], HasCallStack) => FilePath -> ((Contract, Contract cp st) -> IO [TestTree]) -> IO [TestTree]
+ Michelson.Test.Import: testTreesWithContractL :: (Each [Typeable, SingI] [ToT cp, ToT st], HasCallStack) => FilePath -> ((Contract, Contract cp st) -> IO [TestTree]) -> IO [TestTree]
+ Michelson.Test.Import: testTreesWithTypedContract :: (Each [Typeable, SingI] [cp, st], HasCallStack) => FilePath -> (Contract cp st -> IO [TestTree]) -> IO [TestTree]
+ Michelson.Test.Import: testTreesWithUntypedContract :: HasCallStack => FilePath -> (Contract -> IO [TestTree]) -> IO [TestTree]
+ Michelson.Test.Integrational: (?-) :: Text -> a -> (Text, a)
+ Michelson.Test.Integrational: CustomValidationError :: Text -> ValidationError
+ Michelson.Test.Integrational: UnexpectedUpdates :: NonEmpty GStateUpdate -> ValidationError
+ Michelson.Test.Integrational: branchout :: HasCallStack => [(Text, IntegrationalScenario)] -> IntegrationalScenario
+ Michelson.Test.Integrational: expectNoStorageUpdates :: SuccessValidator
+ Michelson.Test.Integrational: expectNoUpdates :: SuccessValidator
+ Michelson.Test.Integrational: infixr 0 ?-
+ Michelson.Test.Integrational: instance Formatting.Buildable.Buildable Michelson.Test.Integrational.ScenarioBranchName
+ Michelson.Test.Integrational: instance Formatting.Buildable.Buildable Michelson.Test.Integrational.ScenarioError
+ Michelson.Test.Integrational: modifyNow :: (Timestamp -> Timestamp) -> IntegrationalScenarioM ()
+ Michelson.Test.Integrational: offshoot :: Text -> IntegrationalScenario -> IntegrationalScenarioM ()
+ Michelson.Test.Integrational: rewindTime :: Integer -> IntegrationalScenarioM ()
+ Michelson.Test.Integrational: setChainId :: ChainId -> IntegrationalScenarioM ()
+ Michelson.Text: instance Data.Hashable.Class.Hashable Michelson.Text.MText
+ Michelson.Text: labelToMText :: KnownSymbol name => Label name -> MText
+ Michelson.Text: mtextHeadToUpper :: HasCallStack => MText -> MText
+ Michelson.Text: symbolToMText :: forall name. KnownSymbol name => MText
+ Michelson.TypeCheck: typeCheckStorageOrParameter :: StorageOrParameter -> Value -> TcOriginatedContracts -> Contract -> Either TCError SomeValue
+ Michelson.TypeCheck.Error: IllegalEntryPoint :: EpNameFromRefAnnError -> TCTypeError
+ Michelson.TypeCheck.Error: IllegalParamDecl :: ParamEpError -> TCTypeError
+ Michelson.TypeCheck.Error: InvalidAddress :: ParseEpAddressError -> TCTypeError
+ Michelson.TypeCheck.Error: InvalidKeyHash :: CryptoParseError -> TCTypeError
+ Michelson.TypeCheck.Error: InvalidTimestamp :: TCTypeError
+ Michelson.TypeCheck.Error: InvalidValueType :: T -> TCTypeError
+ Michelson.TypeCheck.Error: MutezOverflow :: TCTypeError
+ Michelson.TypeCheck.Error: NegativeNat :: TCTypeError
+ Michelson.TypeCheck.Error: NotEnoughDig :: NotEnoughItemsInstr
+ Michelson.TypeCheck.Error: NotEnoughDip :: NotEnoughItemsInstr
+ Michelson.TypeCheck.Error: NotEnoughDrop :: NotEnoughItemsInstr
+ Michelson.TypeCheck.Error: NotEnoughDug :: NotEnoughItemsInstr
+ Michelson.TypeCheck.Error: NotEnoughItemsOnStack :: !Word -> !NotEnoughItemsInstr -> TCTypeError
+ Michelson.TypeCheck.Error: data NotEnoughItemsInstr
+ Michelson.TypeCheck.Error: instance Formatting.Buildable.Buildable Michelson.TypeCheck.Error.NotEnoughItemsInstr
+ Michelson.TypeCheck.Error: instance GHC.Classes.Eq Michelson.TypeCheck.Error.NotEnoughItemsInstr
+ Michelson.TypeCheck.Error: instance GHC.Show.Show Michelson.TypeCheck.Error.NotEnoughItemsInstr
+ Michelson.TypeCheck.Instr: Parameter :: StorageOrParameter
+ Michelson.TypeCheck.Instr: Storage :: StorageOrParameter
+ Michelson.TypeCheck.Instr: data StorageOrParameter
+ Michelson.TypeCheck.Instr: typeCheckStorageOrParameter :: StorageOrParameter -> Value -> TcOriginatedContracts -> Contract -> Either TCError SomeValue
+ Michelson.TypeCheck.TypeCheck: mapTCError :: (TCError -> TCError) -> TypeCheckInstr a -> TypeCheckInstr a
+ Michelson.TypeCheck.TypeCheck: runTypeCheckIsolated :: TypeCheck a -> Either TCError a
+ Michelson.TypeCheck.Types: Parameter :: StorageOrParameter
+ Michelson.TypeCheck.Types: Storage :: StorageOrParameter
+ Michelson.TypeCheck.Types: data SomeNotedValue
+ Michelson.TypeCheck.Types: data StorageOrParameter
+ Michelson.TypeCheck.Types: instance GHC.Classes.Eq Michelson.TypeCheck.Types.StorageOrParameter
+ Michelson.TypeCheck.Types: instance GHC.Show.Show Michelson.TypeCheck.Types.SomeNotedValue
+ Michelson.TypeCheck.Types: mapSomeContract :: (forall inp out. Instr inp out -> Instr inp out) -> SomeContract -> SomeContract
+ Michelson.Typed.Aliases: type SomeConstrainedValue = SomeConstrainedValue' Instr
+ Michelson.Typed.Aliases: type SomeValue = SomeValue' Instr
+ Michelson.Typed.Annotation: [NTChainId] :: TypeAnn -> Notes 'TChainId
+ Michelson.Typed.Annotation: instance GHC.Show.Show (Michelson.Typed.Annotation.Notes t)
+ Michelson.Typed.Annotation: starNotes :: forall t. SingI t => Notes t
+ Michelson.Typed.Arith: class CompareOp n
+ Michelson.Typed.Arith: compareOp :: CompareOp n => CValue n -> CValue n -> Integer
+ Michelson.Typed.Arith: instance (n Data.Type.Equality.~ m, Michelson.Typed.Arith.CompareOp n) => Michelson.Typed.Arith.ArithOp Michelson.Typed.Arith.Compare n m
+ Michelson.Typed.Arith: instance Michelson.Typed.Arith.CompareOp 'Michelson.Untyped.Type.CAddress
+ Michelson.Typed.Arith: instance Michelson.Typed.Arith.CompareOp 'Michelson.Untyped.Type.CBool
+ Michelson.Typed.Arith: instance Michelson.Typed.Arith.CompareOp 'Michelson.Untyped.Type.CBytes
+ Michelson.Typed.Arith: instance Michelson.Typed.Arith.CompareOp 'Michelson.Untyped.Type.CInt
+ Michelson.Typed.Arith: instance Michelson.Typed.Arith.CompareOp 'Michelson.Untyped.Type.CKeyHash
+ Michelson.Typed.Arith: instance Michelson.Typed.Arith.CompareOp 'Michelson.Untyped.Type.CMutez
+ Michelson.Typed.Arith: instance Michelson.Typed.Arith.CompareOp 'Michelson.Untyped.Type.CNat
+ Michelson.Typed.Arith: instance Michelson.Typed.Arith.CompareOp 'Michelson.Untyped.Type.CString
+ Michelson.Typed.Arith: instance Michelson.Typed.Arith.CompareOp 'Michelson.Untyped.Type.CTimestamp
+ Michelson.Typed.Convert: convertFullContract :: forall param store. (SingI param, SingI store) => FullContract param store -> Contract
+ Michelson.Typed.Doc: buildInstrDoc :: Instr inp out -> ContractDoc
+ Michelson.Typed.Doc: cutInstrNonDoc :: (forall i o. Instr i o -> Instr i o) -> Instr inp out -> Instr s s
+ Michelson.Typed.Doc: modifyInstrDoc :: DocItem i => (i -> i) -> Instr inp out -> Instr inp out
+ Michelson.Typed.EntryPoints: AcLeft :: ArmCoord
+ Michelson.Typed.EntryPoints: AcRight :: ArmCoord
+ Michelson.Typed.EntryPoints: EntryPointCall :: EpName -> Proxy param -> EpLiftSequence arg param -> EntryPointCallT
+ Michelson.Typed.EntryPoints: EpAddress :: Address -> EpName -> EpAddress
+ Michelson.Typed.EntryPoints: EpNameUnsafe :: Text -> EpName
+ Michelson.Typed.EntryPoints: InEpNameBadAnnotation :: FieldAnn -> EpNameFromRefAnnError
+ Michelson.Typed.EntryPoints: ParamEpDuplicatedNames :: NonEmpty EpName -> ParamEpError
+ Michelson.Typed.EntryPoints: ParamEpUncallableArm :: ArmCoords -> ParamEpError
+ Michelson.Typed.EntryPoints: ParamNotesUnsafe :: Notes t -> ParamNotes
+ Michelson.Typed.EntryPoints: ParseEpAddressBadAddress :: ParseAddressError -> ParseEpAddressError
+ Michelson.Typed.EntryPoints: ParseEpAddressRefAnnError :: EpNameFromRefAnnError -> ParseEpAddressError
+ Michelson.Typed.EntryPoints: SomeEpc :: EntryPointCallT param arg -> SomeEntryPointCallT
+ Michelson.Typed.EntryPoints: [EplArgHere] :: EpLiftSequence arg arg
+ Michelson.Typed.EntryPoints: [EplWrapLeft] :: EpLiftSequence arg subparam -> EpLiftSequence arg ( 'TOr subparam r)
+ Michelson.Typed.EntryPoints: [EplWrapRight] :: EpLiftSequence arg subparam -> EpLiftSequence arg ( 'TOr l subparam)
+ Michelson.Typed.EntryPoints: [eaAddress] :: EpAddress -> Address
+ Michelson.Typed.EntryPoints: [eaEntryPoint] :: EpAddress -> EpName
+ Michelson.Typed.EntryPoints: [epcLiftSequence] :: EntryPointCallT -> EpLiftSequence arg param
+ Michelson.Typed.EntryPoints: [epcName] :: EntryPointCallT -> EpName
+ Michelson.Typed.EntryPoints: [epcParamProxy] :: EntryPointCallT -> Proxy param
+ Michelson.Typed.EntryPoints: [unEpName] :: EpName -> Text
+ Michelson.Typed.EntryPoints: [unParamNotes] :: ParamNotes -> Notes t
+ Michelson.Typed.EntryPoints: data ArmCoord
+ Michelson.Typed.EntryPoints: data EntryPointCallT (param :: T) (arg :: T)
+ Michelson.Typed.EntryPoints: data EpAddress
+ Michelson.Typed.EntryPoints: data EpLiftSequence (arg :: T) (param :: T)
+ Michelson.Typed.EntryPoints: data EpNameFromRefAnnError
+ Michelson.Typed.EntryPoints: data ParamEpError
+ Michelson.Typed.EntryPoints: data ParseEpAddressError
+ Michelson.Typed.EntryPoints: data SomeEntryPointCallT (arg :: T)
+ Michelson.Typed.EntryPoints: epNameFromParamAnn :: FieldAnn -> Maybe EpName
+ Michelson.Typed.EntryPoints: epNameFromRefAnn :: FieldAnn -> Either EpNameFromRefAnnError EpName
+ Michelson.Typed.EntryPoints: epNameToParamAnn :: EpName -> FieldAnn
+ Michelson.Typed.EntryPoints: epNameToRefAnn :: EpName -> FieldAnn
+ Michelson.Typed.EntryPoints: formatEpAddress :: EpAddress -> Text
+ Michelson.Typed.EntryPoints: instance (param Data.Type.Equality.~ arg) => Data.Default.Class.Default (Michelson.Typed.EntryPoints.EntryPointCallT param arg)
+ Michelson.Typed.EntryPoints: instance Data.Default.Class.Default Michelson.Typed.EntryPoints.EpName
+ Michelson.Typed.EntryPoints: instance Formatting.Buildable.Buildable (Michelson.Typed.EntryPoints.EntryPointCallT param arg)
+ Michelson.Typed.EntryPoints: instance Formatting.Buildable.Buildable (Michelson.Typed.EntryPoints.EpLiftSequence arg param)
+ Michelson.Typed.EntryPoints: instance Formatting.Buildable.Buildable (Michelson.Typed.EntryPoints.SomeEntryPointCallT arg)
+ Michelson.Typed.EntryPoints: instance Formatting.Buildable.Buildable Michelson.Typed.EntryPoints.ArmCoord
+ Michelson.Typed.EntryPoints: instance Formatting.Buildable.Buildable Michelson.Typed.EntryPoints.EpAddress
+ Michelson.Typed.EntryPoints: instance Formatting.Buildable.Buildable Michelson.Typed.EntryPoints.EpName
+ Michelson.Typed.EntryPoints: instance Formatting.Buildable.Buildable Michelson.Typed.EntryPoints.EpNameFromRefAnnError
+ Michelson.Typed.EntryPoints: instance Formatting.Buildable.Buildable Michelson.Typed.EntryPoints.ParamEpError
+ Michelson.Typed.EntryPoints: instance Formatting.Buildable.Buildable Michelson.Typed.EntryPoints.ParseEpAddressError
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Eq (Michelson.Typed.EntryPoints.EntryPointCallT param arg)
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Eq (Michelson.Typed.EntryPoints.EpLiftSequence arg param)
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Eq (Michelson.Typed.EntryPoints.ParamNotes t)
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Eq (Michelson.Typed.EntryPoints.SomeEntryPointCallT arg)
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Eq Michelson.Typed.EntryPoints.ArmCoord
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Eq Michelson.Typed.EntryPoints.EpAddress
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Eq Michelson.Typed.EntryPoints.EpName
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Eq Michelson.Typed.EntryPoints.EpNameFromRefAnnError
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Eq Michelson.Typed.EntryPoints.ParamEpError
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Eq Michelson.Typed.EntryPoints.ParseEpAddressError
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Ord Michelson.Typed.EntryPoints.EpAddress
+ Michelson.Typed.EntryPoints: instance GHC.Classes.Ord Michelson.Typed.EntryPoints.EpName
+ Michelson.Typed.EntryPoints: instance GHC.Show.Show (Michelson.Typed.EntryPoints.EntryPointCallT param arg)
+ Michelson.Typed.EntryPoints: instance GHC.Show.Show (Michelson.Typed.EntryPoints.EpLiftSequence arg param)
+ Michelson.Typed.EntryPoints: instance GHC.Show.Show (Michelson.Typed.EntryPoints.ParamNotes t)
+ Michelson.Typed.EntryPoints: instance GHC.Show.Show (Michelson.Typed.EntryPoints.SomeEntryPointCallT arg)
+ Michelson.Typed.EntryPoints: instance GHC.Show.Show Michelson.Typed.EntryPoints.ArmCoord
+ Michelson.Typed.EntryPoints: instance GHC.Show.Show Michelson.Typed.EntryPoints.EpAddress
+ Michelson.Typed.EntryPoints: instance GHC.Show.Show Michelson.Typed.EntryPoints.EpName
+ Michelson.Typed.EntryPoints: instance GHC.Show.Show Michelson.Typed.EntryPoints.EpNameFromRefAnnError
+ Michelson.Typed.EntryPoints: instance GHC.Show.Show Michelson.Typed.EntryPoints.ParamEpError
+ Michelson.Typed.EntryPoints: instance GHC.Show.Show Michelson.Typed.EntryPoints.ParseEpAddressError
+ Michelson.Typed.EntryPoints: instance Michelson.Typed.Scope.ParameterScope arg => Data.Default.Class.Default (Michelson.Typed.EntryPoints.SomeEntryPointCallT arg)
+ Michelson.Typed.EntryPoints: instance Test.QuickCheck.Arbitrary.Arbitrary Michelson.Untyped.Annotation.FieldAnn => Test.QuickCheck.Arbitrary.Arbitrary Michelson.Typed.EntryPoints.EpAddress
+ Michelson.Typed.EntryPoints: instance Test.QuickCheck.Arbitrary.Arbitrary Michelson.Untyped.Annotation.FieldAnn => Test.QuickCheck.Arbitrary.Arbitrary Michelson.Typed.EntryPoints.EpName
+ Michelson.Typed.EntryPoints: mformatEpAddress :: EpAddress -> MText
+ Michelson.Typed.EntryPoints: mkEntryPointCall :: ParameterScope param => EpName -> (Sing param, Notes param) -> (forall arg. ParameterScope arg => (Notes arg, EntryPointCallT param arg) -> r) -> Maybe r
+ Michelson.Typed.EntryPoints: mkParamNotes :: Notes t -> Either ParamEpError (ParamNotes t)
+ Michelson.Typed.EntryPoints: newtype EpName
+ Michelson.Typed.EntryPoints: newtype ParamNotes (t :: T)
+ Michelson.Typed.EntryPoints: parseEpAddress :: Text -> Either ParseEpAddressError EpAddress
+ Michelson.Typed.EntryPoints: pattern NoEpName :: EpName
+ Michelson.Typed.EntryPoints: sepcName :: SomeEntryPointCallT arg -> EpName
+ Michelson.Typed.EntryPoints: tyImplicitAccountParam :: (Sing 'TUnit, Notes 'TUnit)
+ Michelson.Typed.EntryPoints: type ArmCoords = [ArmCoord]
+ Michelson.Typed.EntryPoints: unsafeParseEpAddress :: HasCallStack => Text -> EpAddress
+ Michelson.Typed.Extract: withUType :: Type -> (forall t. (Typeable t, SingI t) => (Sing t, Notes t) -> r) -> r
+ Michelson.Typed.Haskell: AnyIsoValue :: (forall a. IsoValue a => a) -> AnyIsoValue
+ Michelson.Typed.Haskell: ComposeCtorNotFound :: ComposeResult a
+ Michelson.Typed.Haskell: ComposeFieldTypeMismatch :: TypeRep -> TypeRep -> ComposeResult a
+ Michelson.Typed.Haskell: ComposeOk :: a -> ComposeResult a
+ Michelson.Typed.Haskell: ContractRef :: Address -> SomeEntryPointCall arg -> ContractRef
+ Michelson.Typed.Haskell: L :: Branch
+ Michelson.Typed.Haskell: R :: Branch
+ Michelson.Typed.Haskell: S :: Branch
+ Michelson.Typed.Haskell: WithinParens :: Bool -> WithinParens
+ Michelson.Typed.Haskell: [DType] :: TypeHasDoc a => Proxy a -> DType
+ Michelson.Typed.Haskell: [SomeIsoValue] :: (Typeable a, IsoValue a) => a -> SomeIsoValue
+ Michelson.Typed.Haskell: [SomeTypeWithDoc] :: TypeHasDoc td => Proxy td -> SomeTypeWithDoc
+ Michelson.Typed.Haskell: [crAddress] :: ContractRef -> Address
+ Michelson.Typed.Haskell: [crEntryPoint] :: ContractRef -> SomeEntryPointCall arg
+ Michelson.Typed.Haskell: applyWithinParens :: WithinParens -> Markdown -> Markdown
+ Michelson.Typed.Haskell: buildADTRep :: forall a. (WithinParens -> a -> Markdown) -> ADTRep a -> Markdown
+ Michelson.Typed.Haskell: class GTypeHasDoc (x :: Type -> Type)
+ Michelson.Typed.Haskell: class HaveCommonTypeCtor a b
+ Michelson.Typed.Haskell: class IsHomomorphic a
+ Michelson.Typed.Haskell: class IsoValuesStack (ts :: [Type])
+ Michelson.Typed.Haskell: class Typeable a => TypeHasDoc a
+ Michelson.Typed.Haskell: coerceContractRef :: ToT a ~ ToT b => ContractRef a -> ContractRef b
+ Michelson.Typed.Haskell: concreteTypeDocHaskellRep :: forall a b. (Typeable a, IsoValue a, Generic a, GTypeHasDoc (Rep a), HaveCommonTypeCtor b a) => TypeDocHaskellRep b
+ Michelson.Typed.Haskell: concreteTypeDocHaskellRepUnsafe :: forall a b. (Typeable a, IsoValue a, Generic a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep b
+ Michelson.Typed.Haskell: concreteTypeDocMichelsonRep :: forall a b. (Typeable a, SingI (ToT a), HaveCommonTypeCtor b a) => TypeDocMichelsonRep b
+ Michelson.Typed.Haskell: concreteTypeDocMichelsonRepUnsafe :: forall a b. (Typeable a, SingI (ToT a)) => TypeDocMichelsonRep b
+ Michelson.Typed.Haskell: customTypeDocMdReference :: (Text, DType) -> [DType] -> WithinParens -> Markdown
+ Michelson.Typed.Haskell: data Branch
+ Michelson.Typed.Haskell: data ComposeResult a
+ Michelson.Typed.Haskell: data ContractRef (arg :: Type)
+ Michelson.Typed.Haskell: data DType
+ Michelson.Typed.Haskell: data SomeIsoValue
+ Michelson.Typed.Haskell: data SomeTypeWithDoc
+ Michelson.Typed.Haskell: fromTaggedVal :: LooseSumC dt => (Text, SomeValue) -> ComposeResult dt
+ Michelson.Typed.Haskell: fromValStack :: IsoValuesStack ts => Rec Value (ToTs ts) -> Rec Identity ts
+ Michelson.Typed.Haskell: genericTypeDocDependencies :: forall a. (Generic a, GTypeHasDoc (Rep a)) => Proxy a -> [SomeTypeWithDoc]
+ Michelson.Typed.Haskell: haskellRepNoFields :: TypeDocHaskellRep a -> TypeDocHaskellRep a
+ Michelson.Typed.Haskell: haskellRepStripFieldPrefix :: HasCallStack => TypeDocHaskellRep a -> TypeDocHaskellRep a
+ Michelson.Typed.Haskell: homomorphicTypeDocHaskellRep :: forall a. (Generic a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep a
+ Michelson.Typed.Haskell: homomorphicTypeDocMdReference :: forall (t :: Type). (Typeable t, TypeHasDoc t, IsHomomorphic t) => Proxy t -> WithinParens -> Markdown
+ Michelson.Typed.Haskell: homomorphicTypeDocMichelsonRep :: forall a. SingI (ToT a) => TypeDocMichelsonRep a
+ Michelson.Typed.Haskell: newtype AnyIsoValue
+ Michelson.Typed.Haskell: newtype WithinParens
+ Michelson.Typed.Haskell: poly1TypeDocMdReference :: forall t (r :: Type) (a :: Type). (r ~ t a, Typeable t, Each '[TypeHasDoc] [r, a], IsHomomorphic t) => Proxy r -> WithinParens -> Markdown
+ Michelson.Typed.Haskell: poly2TypeDocMdReference :: forall t (r :: Type) (a :: Type) (b :: Type). (r ~ t a b, Typeable t, Each '[TypeHasDoc] [r, a, b], IsHomomorphic t) => Proxy r -> WithinParens -> Markdown
+ Michelson.Typed.Haskell: toTaggedVal :: LooseSumC dt => dt -> (Text, SomeValue)
+ Michelson.Typed.Haskell: toValStack :: IsoValuesStack ts => Rec Identity ts -> Rec Value (ToTs ts)
+ Michelson.Typed.Haskell: totsAppendLemma :: forall a b. KnownList a => Dict (ToTs (a ++ b) ~ (ToTs a ++ ToTs b))
+ Michelson.Typed.Haskell: totsKnownLemma :: forall s. KnownList s :- KnownList (ToTs s)
+ Michelson.Typed.Haskell: type ADTRep a = NonEmpty (Text, [(Maybe Text, a)])
+ Michelson.Typed.Haskell: type EntryPointCall param arg = EntryPointCallT (ToT param) (ToT arg)
+ Michelson.Typed.Haskell: type IsGenericIsoValue t = (IsoValue t, Generic t, ToT t ~ GValueType (Rep t))
+ Michelson.Typed.Haskell: type LooseSumC dt = (Generic dt, GLooseSum (Rep dt))
+ Michelson.Typed.Haskell: type Path = [Branch]
+ Michelson.Typed.Haskell: type PolyTypeHasDocC ts = Each '[TypeHasDoc] ts
+ Michelson.Typed.Haskell: type SomeEntryPointCall arg = SomeEntryPointCallT (ToT arg)
+ Michelson.Typed.Haskell: type TypeDocHaskellRep a = Proxy a -> Maybe (Maybe DocTypeRepLHS, ADTRep SomeTypeWithDoc)
+ Michelson.Typed.Haskell: type TypeDocMichelsonRep a = Proxy a -> (Maybe DocTypeRepLHS, T)
+ Michelson.Typed.Haskell: typeDocDependencies :: (TypeHasDoc a, Generic a, GTypeHasDoc (Rep a)) => Proxy a -> [SomeTypeWithDoc]
+ Michelson.Typed.Haskell: typeDocDependencies' :: TypeHasDoc a => Proxy a -> [SomeDocDefinitionItem]
+ Michelson.Typed.Haskell: typeDocHaskellRep :: (TypeHasDoc a, Generic a, GTypeHasDoc (Rep a), IsHomomorphic a) => TypeDocHaskellRep a
+ Michelson.Typed.Haskell: typeDocMdDescription :: TypeHasDoc a => Markdown
+ Michelson.Typed.Haskell: typeDocMdReference :: (TypeHasDoc a, Typeable a, IsHomomorphic a) => Proxy a -> WithinParens -> Markdown
+ Michelson.Typed.Haskell: typeDocMichelsonRep :: (TypeHasDoc a, SingI (ToT a), IsHomomorphic a) => TypeDocMichelsonRep a
+ Michelson.Typed.Haskell: typeDocName :: (TypeHasDoc a, Generic a, KnownSymbol (GenericTypeName a)) => Proxy a -> Text
+ Michelson.Typed.Haskell.Doc: WithinParens :: Bool -> WithinParens
+ Michelson.Typed.Haskell.Doc: [DType] :: TypeHasDoc a => Proxy a -> DType
+ Michelson.Typed.Haskell.Doc: [SomeTypeWithDoc] :: TypeHasDoc td => Proxy td -> SomeTypeWithDoc
+ Michelson.Typed.Haskell.Doc: applyWithinParens :: WithinParens -> Markdown -> Markdown
+ Michelson.Typed.Haskell.Doc: buildADTRep :: forall a. (WithinParens -> a -> Markdown) -> ADTRep a -> Markdown
+ Michelson.Typed.Haskell.Doc: class GTypeHasDoc (x :: Type -> Type)
+ Michelson.Typed.Haskell.Doc: class HaveCommonTypeCtor a b
+ Michelson.Typed.Haskell.Doc: class IsHomomorphic a
+ Michelson.Typed.Haskell.Doc: class Typeable a => TypeHasDoc a
+ Michelson.Typed.Haskell.Doc: concreteTypeDocHaskellRep :: forall a b. (Typeable a, IsoValue a, Generic a, GTypeHasDoc (Rep a), HaveCommonTypeCtor b a) => TypeDocHaskellRep b
+ Michelson.Typed.Haskell.Doc: concreteTypeDocHaskellRepUnsafe :: forall a b. (Typeable a, IsoValue a, Generic a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep b
+ Michelson.Typed.Haskell.Doc: concreteTypeDocMichelsonRep :: forall a b. (Typeable a, SingI (ToT a), HaveCommonTypeCtor b a) => TypeDocMichelsonRep b
+ Michelson.Typed.Haskell.Doc: concreteTypeDocMichelsonRepUnsafe :: forall a b. (Typeable a, SingI (ToT a)) => TypeDocMichelsonRep b
+ Michelson.Typed.Haskell.Doc: customTypeDocMdReference :: (Text, DType) -> [DType] -> WithinParens -> Markdown
+ Michelson.Typed.Haskell.Doc: data DType
+ Michelson.Typed.Haskell.Doc: data SomeTypeWithDoc
+ Michelson.Typed.Haskell.Doc: genericTypeDocDependencies :: forall a. (Generic a, GTypeHasDoc (Rep a)) => Proxy a -> [SomeTypeWithDoc]
+ Michelson.Typed.Haskell.Doc: haskellRepNoFields :: TypeDocHaskellRep a -> TypeDocHaskellRep a
+ Michelson.Typed.Haskell.Doc: haskellRepStripFieldPrefix :: HasCallStack => TypeDocHaskellRep a -> TypeDocHaskellRep a
+ Michelson.Typed.Haskell.Doc: homomorphicTypeDocHaskellRep :: forall a. (Generic a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep a
+ Michelson.Typed.Haskell.Doc: homomorphicTypeDocMdReference :: forall (t :: Type). (Typeable t, TypeHasDoc t, IsHomomorphic t) => Proxy t -> WithinParens -> Markdown
+ Michelson.Typed.Haskell.Doc: homomorphicTypeDocMichelsonRep :: forall a. SingI (ToT a) => TypeDocMichelsonRep a
+ Michelson.Typed.Haskell.Doc: instance (Michelson.Typed.Haskell.Doc.GProductHasDoc x, GHC.TypeLits.KnownSymbol ctor) => Michelson.Typed.Haskell.Doc.GTypeHasDoc (GHC.Generics.C1 ('GHC.Generics.MetaCons ctor _1 _2) x)
+ Michelson.Typed.Haskell.Doc: instance (Michelson.Typed.Haskell.Doc.GProductHasDoc x, Michelson.Typed.Haskell.Doc.GProductHasDoc y) => Michelson.Typed.Haskell.Doc.GProductHasDoc (x GHC.Generics.:*: y)
+ Michelson.Typed.Haskell.Doc: instance (Michelson.Typed.Haskell.Doc.GTypeHasDoc x, Michelson.Typed.Haskell.Doc.GTypeHasDoc y) => Michelson.Typed.Haskell.Doc.GTypeHasDoc (x GHC.Generics.:+: y)
+ Michelson.Typed.Haskell.Doc: instance (Michelson.Typed.Haskell.Doc.PolyCTypeHasDocC '[k], Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[v], GHC.Classes.Ord k) => Michelson.Typed.Haskell.Doc.TypeHasDoc (Data.Map.Internal.Map k v)
+ Michelson.Typed.Haskell.Doc: instance (Michelson.Typed.Haskell.Doc.PolyCTypeHasDocC '[k], Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[v], GHC.Classes.Ord k) => Michelson.Typed.Haskell.Doc.TypeHasDoc (Michelson.Typed.Haskell.Value.BigMap k v)
+ Michelson.Typed.Haskell.Doc: instance (Michelson.Typed.Haskell.Doc.TypeHasDoc (Util.Named.ApplyNamedFunctor f a), GHC.TypeLits.KnownSymbol n, Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.ToT (Util.Named.ApplyNamedFunctor f GHC.Integer.Type.Integer)), Data.Typeable.Internal.Typeable f, Data.Typeable.Internal.Typeable a) => Michelson.Typed.Haskell.Doc.TypeHasDoc (Named.Internal.NamedF f a n)
+ Michelson.Typed.Haskell.Doc: instance (Michelson.Typed.Haskell.Doc.TypeHasDoc a, GHC.TypeLits.KnownSymbol field) => Michelson.Typed.Haskell.Doc.GProductHasDoc (GHC.Generics.S1 ('GHC.Generics.MetaSel ('GHC.Maybe.Just field) _1 _2 _3) (GHC.Generics.Rec0 a))
+ Michelson.Typed.Haskell.Doc: instance (TypeError ...) => Michelson.Typed.Haskell.Doc.GTypeHasDoc GHC.Generics.V1
+ Michelson.Typed.Haskell.Doc: instance Data.String.IsString Michelson.Typed.Haskell.Doc.DocTypeRepLHS
+ Michelson.Typed.Haskell.Doc: instance Formatting.Buildable.Buildable Michelson.Typed.Haskell.Doc.DocTypeRepLHS
+ Michelson.Typed.Haskell.Doc: instance GHC.Classes.Eq Michelson.Typed.Haskell.Doc.DType
+ Michelson.Typed.Haskell.Doc: instance GHC.Classes.Ord Michelson.Typed.Haskell.Doc.DType
+ Michelson.Typed.Haskell.Doc: instance GHC.Show.Show Michelson.Typed.Haskell.Doc.SomeTypeWithDoc
+ Michelson.Typed.Haskell.Doc: instance Michelson.Doc.DocItem Michelson.Typed.Haskell.Doc.DType
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.GProductHasDoc GHC.Generics.U1
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.GTypeHasDoc x => Michelson.Typed.Haskell.Doc.GTypeHasDoc (GHC.Generics.D1 i x)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyCTypeHasDocC '[a] => Michelson.Typed.Haskell.Doc.TypeHasDoc (Data.Set.Internal.Set a)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[a, b, c, d, e, f, g] => Michelson.Typed.Haskell.Doc.TypeHasDoc (a, b, c, d, e, f, g)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[a, b, c, d, e, f] => Michelson.Typed.Haskell.Doc.TypeHasDoc (a, b, c, d, e, f)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[a, b, c, d, e] => Michelson.Typed.Haskell.Doc.TypeHasDoc (a, b, c, d, e)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[a, b, c, d] => Michelson.Typed.Haskell.Doc.TypeHasDoc (a, b, c, d)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[a, b, c] => Michelson.Typed.Haskell.Doc.TypeHasDoc (a, b, c)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[a, b] => Michelson.Typed.Haskell.Doc.TypeHasDoc (a, b)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[a] => Michelson.Typed.Haskell.Doc.TypeHasDoc (GHC.Maybe.Maybe a)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[a] => Michelson.Typed.Haskell.Doc.TypeHasDoc [a]
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[cp] => Michelson.Typed.Haskell.Doc.TypeHasDoc (Michelson.Typed.Haskell.Value.ContractRef cp)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[l, r] => Michelson.Typed.Haskell.Doc.TypeHasDoc (Data.Either.Either l r)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc ()
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Data.ByteString.Internal.ByteString
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc GHC.Integer.Type.Integer
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc GHC.Natural.Natural
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc GHC.Types.Bool
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Michelson.Text.MText
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Michelson.Typed.Aliases.Operation
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Michelson.Typed.EntryPoints.EpAddress
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Tezos.Address.Address
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Tezos.Core.Mutez
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Tezos.Core.Timestamp
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Tezos.Crypto.KeyHash
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Tezos.Crypto.PublicKey
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc Tezos.Crypto.Signature
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.TypeHasDoc a => Michelson.Typed.Haskell.Doc.GProductHasDoc (GHC.Generics.S1 ('GHC.Generics.MetaSel 'GHC.Maybe.Nothing _1 _2 _3) (GHC.Generics.Rec0 a))
+ Michelson.Typed.Haskell.Doc: instance forall k (a :: k). Michelson.Typed.Haskell.Doc.HaveCommonTypeCtor a a
+ Michelson.Typed.Haskell.Doc: instance forall k (a :: k). Michelson.Typed.Haskell.Doc.IsHomomorphic a
+ Michelson.Typed.Haskell.Doc: instance forall k1 k2 (a :: k1 -> k2) (b :: k1). (TypeError ...) => Michelson.Typed.Haskell.Doc.IsHomomorphic (a b)
+ Michelson.Typed.Haskell.Doc: instance forall k1 k2 k3 k4 (ac :: k3 -> k4) (bc :: k1 -> k2) (a :: k3) (b :: k1). Michelson.Typed.Haskell.Doc.HaveCommonTypeCtor ac bc => Michelson.Typed.Haskell.Doc.HaveCommonTypeCtor (ac a) (bc b)
+ Michelson.Typed.Haskell.Doc: newtype WithinParens
+ Michelson.Typed.Haskell.Doc: poly1TypeDocMdReference :: forall t (r :: Type) (a :: Type). (r ~ t a, Typeable t, Each '[TypeHasDoc] [r, a], IsHomomorphic t) => Proxy r -> WithinParens -> Markdown
+ Michelson.Typed.Haskell.Doc: poly2TypeDocMdReference :: forall t (r :: Type) (a :: Type) (b :: Type). (r ~ t a b, Typeable t, Each '[TypeHasDoc] [r, a, b], IsHomomorphic t) => Proxy r -> WithinParens -> Markdown
+ Michelson.Typed.Haskell.Doc: type ADTRep a = NonEmpty (Text, [(Maybe Text, a)])
+ Michelson.Typed.Haskell.Doc: type PolyTypeHasDocC ts = Each '[TypeHasDoc] ts
+ Michelson.Typed.Haskell.Doc: type TypeDocHaskellRep a = Proxy a -> Maybe (Maybe DocTypeRepLHS, ADTRep SomeTypeWithDoc)
+ Michelson.Typed.Haskell.Doc: type TypeDocMichelsonRep a = Proxy a -> (Maybe DocTypeRepLHS, T)
+ Michelson.Typed.Haskell.Doc: typeDocDependencies :: (TypeHasDoc a, Generic a, GTypeHasDoc (Rep a)) => Proxy a -> [SomeTypeWithDoc]
+ Michelson.Typed.Haskell.Doc: typeDocDependencies' :: TypeHasDoc a => Proxy a -> [SomeDocDefinitionItem]
+ Michelson.Typed.Haskell.Doc: typeDocHaskellRep :: (TypeHasDoc a, Generic a, GTypeHasDoc (Rep a), IsHomomorphic a) => TypeDocHaskellRep a
+ Michelson.Typed.Haskell.Doc: typeDocMdDescription :: TypeHasDoc a => Markdown
+ Michelson.Typed.Haskell.Doc: typeDocMdReference :: (TypeHasDoc a, Typeable a, IsHomomorphic a) => Proxy a -> WithinParens -> Markdown
+ Michelson.Typed.Haskell.Doc: typeDocMichelsonRep :: (TypeHasDoc a, SingI (ToT a), IsHomomorphic a) => TypeDocMichelsonRep a
+ Michelson.Typed.Haskell.Doc: typeDocName :: (TypeHasDoc a, Generic a, KnownSymbol (GenericTypeName a)) => Proxy a -> Text
+ Michelson.Typed.Haskell.Instr.Product: instance (Michelson.Typed.Haskell.Instr.Product.GInstrConstruct x, Michelson.Typed.Haskell.Instr.Product.GInstrConstruct y, Util.Type.RSplit (Michelson.Typed.Haskell.Instr.Product.GFieldTypes x) (Michelson.Typed.Haskell.Instr.Product.GFieldTypes y)) => Michelson.Typed.Haskell.Instr.Product.GInstrConstruct (x GHC.Generics.:*: y)
+ Michelson.Typed.Haskell.Instr.Sum: L :: Branch
+ Michelson.Typed.Haskell.Instr.Sum: R :: Branch
+ Michelson.Typed.Haskell.Instr.Sum: S :: Branch
+ Michelson.Typed.Haskell.Instr.Sum: data Branch
+ Michelson.Typed.Haskell.Instr.Sum: instance (Michelson.Typed.Haskell.Instr.Sum.GInstrCase x, Michelson.Typed.Haskell.Instr.Sum.GInstrCase y, Util.Type.RSplit (Michelson.Typed.Haskell.Instr.Sum.GCaseClauses x) (Michelson.Typed.Haskell.Instr.Sum.GCaseClauses y)) => Michelson.Typed.Haskell.Instr.Sum.GInstrCase (x GHC.Generics.:+: y)
+ Michelson.Typed.Haskell.Instr.Sum: instance GHC.Generics.Generic Michelson.Typed.Haskell.Instr.Sum.MyTypeWithNamedField
+ Michelson.Typed.Haskell.Instr.Sum: instance Michelson.Typed.Haskell.Value.IsoValue Michelson.Typed.Haskell.Instr.Sum.MyTypeWithNamedField
+ Michelson.Typed.Haskell.Instr.Sum: type Path = [Branch]
+ Michelson.Typed.Haskell.LooseSum: ComposeCtorNotFound :: ComposeResult a
+ Michelson.Typed.Haskell.LooseSum: ComposeFieldTypeMismatch :: TypeRep -> TypeRep -> ComposeResult a
+ Michelson.Typed.Haskell.LooseSum: ComposeOk :: a -> ComposeResult a
+ Michelson.Typed.Haskell.LooseSum: data ComposeResult a
+ Michelson.Typed.Haskell.LooseSum: fromTaggedVal :: LooseSumC dt => (Text, SomeValue) -> ComposeResult dt
+ Michelson.Typed.Haskell.LooseSum: instance (Data.Typeable.Internal.Typeable a, Michelson.Typed.Haskell.Value.IsoValue a, Data.Typeable.Internal.Typeable (Michelson.Typed.Haskell.Value.ToT a), Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.ToT a)) => Michelson.Typed.Haskell.LooseSum.GAccessField (GHC.Generics.Rec0 a)
+ Michelson.Typed.Haskell.LooseSum: instance (Michelson.Typed.Haskell.LooseSum.GAccessField x, GHC.TypeLits.KnownSymbol ctor) => Michelson.Typed.Haskell.LooseSum.GLooseSum (GHC.Generics.C1 ('GHC.Generics.MetaCons ctor f o) x)
+ Michelson.Typed.Haskell.LooseSum: instance (Michelson.Typed.Haskell.LooseSum.GLooseSum x, Michelson.Typed.Haskell.LooseSum.GLooseSum y) => Michelson.Typed.Haskell.LooseSum.GLooseSum (x GHC.Generics.:+: y)
+ Michelson.Typed.Haskell.LooseSum: instance (TypeError ...) => Michelson.Typed.Haskell.LooseSum.GAccessField (x GHC.Generics.:*: y)
+ Michelson.Typed.Haskell.LooseSum: instance GHC.Base.Functor Michelson.Typed.Haskell.LooseSum.ComposeResult
+ Michelson.Typed.Haskell.LooseSum: instance GHC.Base.Monoid (Michelson.Typed.Haskell.LooseSum.ComposeResult a)
+ Michelson.Typed.Haskell.LooseSum: instance GHC.Base.Semigroup (Michelson.Typed.Haskell.LooseSum.ComposeResult a)
+ Michelson.Typed.Haskell.LooseSum: instance Michelson.Typed.Haskell.LooseSum.GAccessField GHC.Generics.U1
+ Michelson.Typed.Haskell.LooseSum: instance Michelson.Typed.Haskell.LooseSum.GAccessField x => Michelson.Typed.Haskell.LooseSum.GAccessField (GHC.Generics.S1 i x)
+ Michelson.Typed.Haskell.LooseSum: instance Michelson.Typed.Haskell.LooseSum.GLooseSum GHC.Generics.V1
+ Michelson.Typed.Haskell.LooseSum: instance Michelson.Typed.Haskell.LooseSum.GLooseSum x => Michelson.Typed.Haskell.LooseSum.GLooseSum (GHC.Generics.D1 i x)
+ Michelson.Typed.Haskell.LooseSum: toTaggedVal :: LooseSumC dt => dt -> (Text, SomeValue)
+ Michelson.Typed.Haskell.LooseSum: type LooseSumC dt = (Generic dt, GLooseSum (Rep dt))
+ Michelson.Typed.Haskell.Value: AnyIsoValue :: (forall a. IsoValue a => a) -> AnyIsoValue
+ Michelson.Typed.Haskell.Value: ContractRef :: Address -> SomeEntryPointCall arg -> ContractRef
+ Michelson.Typed.Haskell.Value: [SomeIsoValue] :: (Typeable a, IsoValue a) => a -> SomeIsoValue
+ Michelson.Typed.Haskell.Value: [crAddress] :: ContractRef -> Address
+ Michelson.Typed.Haskell.Value: [crEntryPoint] :: ContractRef -> SomeEntryPointCall arg
+ Michelson.Typed.Haskell.Value: class IsoValuesStack (ts :: [Type])
+ Michelson.Typed.Haskell.Value: coerceContractRef :: ToT a ~ ToT b => ContractRef a -> ContractRef b
+ Michelson.Typed.Haskell.Value: data ContractRef (arg :: Type)
+ Michelson.Typed.Haskell.Value: data SomeIsoValue
+ Michelson.Typed.Haskell.Value: fromValStack :: IsoValuesStack ts => Rec Value (ToTs ts) -> Rec Identity ts
+ Michelson.Typed.Haskell.Value: instance (Michelson.Typed.Haskell.Value.IsoValue t, Michelson.Typed.Haskell.Value.IsoValuesStack st) => Michelson.Typed.Haskell.Value.IsoValuesStack (t : st)
+ Michelson.Typed.Haskell.Value: instance Formatting.Buildable.Buildable (Michelson.Typed.Haskell.Value.ContractRef arg)
+ Michelson.Typed.Haskell.Value: instance GHC.Classes.Eq (Michelson.Typed.Haskell.Value.ContractRef arg)
+ Michelson.Typed.Haskell.Value: instance GHC.Show.Show (Michelson.Typed.Haskell.Value.ContractRef arg)
+ Michelson.Typed.Haskell.Value: instance Michelson.Typed.Haskell.Value.IsoCValue Michelson.Typed.EntryPoints.EpAddress
+ Michelson.Typed.Haskell.Value: instance Michelson.Typed.Haskell.Value.IsoValue (Michelson.Typed.Haskell.Value.ContractRef arg)
+ Michelson.Typed.Haskell.Value: instance Michelson.Typed.Haskell.Value.IsoValue Michelson.Typed.EntryPoints.EpAddress
+ Michelson.Typed.Haskell.Value: instance Michelson.Typed.Haskell.Value.IsoValue Tezos.Core.ChainId
+ Michelson.Typed.Haskell.Value: instance Michelson.Typed.Haskell.Value.IsoValuesStack '[]
+ Michelson.Typed.Haskell.Value: newtype AnyIsoValue
+ Michelson.Typed.Haskell.Value: toValStack :: IsoValuesStack ts => Rec Identity ts -> Rec Value (ToTs ts)
+ Michelson.Typed.Haskell.Value: totsAppendLemma :: forall a b. KnownList a => Dict (ToTs (a ++ b) ~ (ToTs a ++ ToTs b))
+ Michelson.Typed.Haskell.Value: totsKnownLemma :: forall s. KnownList s :- KnownList (ToTs s)
+ Michelson.Typed.Haskell.Value: type EntryPointCall param arg = EntryPointCallT (ToT param) (ToT arg)
+ Michelson.Typed.Haskell.Value: type IsGenericIsoValue t = (IsoValue t, Generic t, ToT t ~ GValueType (Rep t))
+ Michelson.Typed.Haskell.Value: type SomeEntryPointCall arg = SomeEntryPointCallT (ToT arg)
+ Michelson.Typed.Instr: DOC_ITEM :: SomeDocItem -> ExtInstr s
+ Michelson.Typed.Instr: FullContract :: Contract cp st -> ParamNotes cp -> Notes st -> FullContract cp st
+ Michelson.Typed.Instr: [APPLY] :: forall a b c s. ConstantScope a => Instr (a : ( 'TLambda ( 'TPair a b) c : s)) ( 'TLambda b c : s)
+ Michelson.Typed.Instr: [AnnCAR] :: FieldAnn -> Instr ( 'TPair a b : s) (a : s)
+ Michelson.Typed.Instr: [AnnCDR] :: FieldAnn -> Instr ( 'TPair a b : s) (b : s)
+ Michelson.Typed.Instr: [CHAIN_ID] :: Instr s ( 'TChainId : s)
+ Michelson.Typed.Instr: [DIG] :: forall (n :: Peano) inp out a. ConstraintDIG n inp out a => Sing n -> Instr inp out
+ Michelson.Typed.Instr: [DIPN] :: forall (n :: Peano) inp out s s'. ConstraintDIPN n inp out s s' => Sing n -> Instr s s' -> Instr inp out
+ Michelson.Typed.Instr: [DROPN] :: forall (n :: Peano) s. (SingI n, KnownPeano n, RequireLongerOrSameLength s n) => Sing n -> Instr s (Drop n s)
+ Michelson.Typed.Instr: [DUG] :: forall (n :: Peano) inp out a. ConstraintDUG n inp out a => Sing n -> Instr inp out
+ Michelson.Typed.Instr: [DocGroup] :: DocGrouping -> Instr inp out -> Instr inp out
+ Michelson.Typed.Instr: [EMPTY_BIG_MAP] :: (Typeable a, Typeable b, SingI a, SingI b) => Instr s ( 'TBigMap a b : s)
+ Michelson.Typed.Instr: [FrameInstr] :: forall a b s. (KnownList a, KnownList b) => Proxy s -> Instr a b -> Instr (a ++ s) (b ++ s)
+ Michelson.Typed.Instr: [InstrWithNotes] :: PackedNotes b -> Instr a b -> Instr a b
+ Michelson.Typed.Instr: [PackedNotes] :: Notes a -> Sing a -> PackedNotes (a : s)
+ Michelson.Typed.Instr: [fcCode] :: FullContract cp st -> Contract cp st
+ Michelson.Typed.Instr: [fcParamNotesSafe] :: FullContract cp st -> ParamNotes cp
+ Michelson.Typed.Instr: [fcStoreNotes] :: FullContract cp st -> Notes st
+ Michelson.Typed.Instr: data FullContract cp st
+ Michelson.Typed.Instr: data PackedNotes a
+ Michelson.Typed.Instr: fcParamNotes :: FullContract cp st -> Notes cp
+ Michelson.Typed.Instr: instance Control.DeepSeq.NFData (Michelson.Typed.Instr.Instr inp out)
+ Michelson.Typed.Instr: instance GHC.Base.Monoid (Michelson.Typed.Instr.Instr s s)
+ Michelson.Typed.Instr: instance GHC.Base.Semigroup (Michelson.Typed.Instr.Instr s s)
+ Michelson.Typed.Instr: instance GHC.Show.Show (Michelson.Typed.Instr.FullContract cp st)
+ Michelson.Typed.Instr: instance GHC.Show.Show (Michelson.Typed.Instr.PackedNotes a)
+ Michelson.Typed.Instr: mapFullContractCode :: (Contract cp st -> Contract cp st) -> FullContract cp st -> FullContract cp st
+ Michelson.Typed.Instr: pattern CAR :: Instr ( 'TPair a b : s) (a : s)
+ Michelson.Typed.Instr: pattern CDR :: Instr ( 'TPair a b : s) (b : s)
+ Michelson.Typed.Instr: type ConstraintDIG n inp out a = ConstraintDIG' T n inp out a
+ Michelson.Typed.Instr: type ConstraintDIG' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) = (SingI n, KnownPeano n, RequireLongerThan inp n, inp ~ (Take n inp ++ (a : Drop ( 'S n) inp)), out ~ (a : Take n inp ++ Drop ( 'S n) inp))
+ Michelson.Typed.Instr: type ConstraintDIPN n inp out s s' = ConstraintDIPN' T n inp out s s'
+ Michelson.Typed.Instr: type ConstraintDIPN' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (s :: [kind]) (s' :: [kind]) = (SingI n, KnownPeano n, RequireLongerOrSameLength inp n, ((Take n inp) ++ s) ~ inp, ((Take n inp) ++ s') ~ out)
+ Michelson.Typed.Instr: type ConstraintDUG n inp out a = ConstraintDUG' T n inp out a
+ Michelson.Typed.Instr: type ConstraintDUG' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) = (SingI n, KnownPeano n, RequireLongerThan out n, inp ~ (a : Drop ( 'S 'Z) inp), out ~ (Take n (Drop ( 'S 'Z) inp) ++ (a : Drop ( 'S n) inp)))
+ Michelson.Typed.Scope: ContractAbsent :: ContractPresence
+ Michelson.Typed.Scope: ContractPresent :: ContractPresence
+ Michelson.Typed.Scope: NestedBigMapsAbsent :: NestedBigMapsPresence
+ Michelson.Typed.Scope: NestedBigMapsPresent :: NestedBigMapsPresence
+ Michelson.Typed.Scope: Sub :: (a -> Dict b) -> (:-) a b
+ Michelson.Typed.Scope: checkContractTypePresence :: Sing (ty :: T) -> ContractPresence ty
+ Michelson.Typed.Scope: checkNestedBigMapsPresence :: Sing (ty :: T) -> NestedBigMapsPresence ty
+ Michelson.Typed.Scope: class (ContainsContract t ~ 'False) => HasNoContract t
+ Michelson.Typed.Scope: class (ContainsNestedBigMaps t ~ 'False) => HasNoNestedBigMaps t
+ Michelson.Typed.Scope: contractTypeAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoContract t)
+ Michelson.Typed.Scope: data ContractPresence (t :: T)
+ Michelson.Typed.Scope: data NestedBigMapsPresence (t :: T)
+ Michelson.Typed.Scope: forbiddenContractType :: forall t a. (SingI t, ForbidContract t) => (HasNoContract t => a) -> a
+ Michelson.Typed.Scope: forbiddenNestedBigMaps :: forall t a. (SingI t, ForbidNestedBigMaps t) => (HasNoNestedBigMaps t => a) -> a
+ Michelson.Typed.Scope: infixr 9 :-
+ Michelson.Typed.Scope: instance (Michelson.Typed.Scope.ContainsContract t Data.Type.Equality.~ 'GHC.Types.False) => Michelson.Typed.Scope.HasNoContract t
+ Michelson.Typed.Scope: instance (Michelson.Typed.Scope.ContainsNestedBigMaps t Data.Type.Equality.~ 'GHC.Types.False) => Michelson.Typed.Scope.HasNoNestedBigMaps t
+ Michelson.Typed.Scope: nestedBigMapsAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoNestedBigMaps t)
+ Michelson.Typed.Scope: newtype (:-) a b
+ Michelson.Typed.Scope: properConstantEvi :: forall t. ProperConstantBetterErrors t :- ConstantScope t
+ Michelson.Typed.Scope: properPackedValEvi :: forall t. ProperPackedValBetterErrors t :- PackedValScope t
+ Michelson.Typed.Scope: properParameterEvi :: forall t. ProperParameterBetterErrors t :- ParameterScope t
+ Michelson.Typed.Scope: properPrintedValEvi :: forall t. ProperPrintedValBetterErrors t :- PrintedValScope t
+ Michelson.Typed.Scope: properStorageEvi :: forall t. ProperStorageBetterErrors t :- StorageScope t
+ Michelson.Typed.Scope: properUnpackedValEvi :: forall t. ProperUnpackedValBetterErrors t :- UnpackedValScope t
+ Michelson.Typed.Scope: type ConstantScope t = (SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t)
+ Michelson.Typed.Scope: type ForbidContract t = FailOnContractFound (ContainsContract t)
+ Michelson.Typed.Scope: type ForbidNestedBigMaps t = FailOnNestedBigMapsFound (ContainsNestedBigMaps t)
+ Michelson.Typed.Scope: type PackedValScope t = (SingI t, HasNoOp t, HasNoBigMap t)
+ Michelson.Typed.Scope: type ParameterScope t = (Typeable t, SingI t, HasNoOp t, HasNoNestedBigMaps t)
+ Michelson.Typed.Scope: type PrintedValScope t = (SingI t, HasNoOp t)
+ Michelson.Typed.Scope: type ProperConstantBetterErrors t = (SingI t, ForbidOp t, ForbidBigMap t, ForbidContract t)
+ Michelson.Typed.Scope: type ProperPackedValBetterErrors t = (SingI t, ForbidOp t, ForbidBigMap t)
+ Michelson.Typed.Scope: type ProperParameterBetterErrors t = (Typeable t, SingI t, ForbidOp t, ForbidNestedBigMaps t)
+ Michelson.Typed.Scope: type ProperPrintedValBetterErrors t = (SingI t, ForbidOp t)
+ Michelson.Typed.Scope: type ProperStorageBetterErrors t = (Typeable t, SingI t, ForbidOp t, ForbidNestedBigMaps t, ForbidContract t)
+ Michelson.Typed.Scope: type ProperUnpackedValBetterErrors t = (ProperPackedValBetterErrors t, ProperConstantBetterErrors t)
+ Michelson.Typed.Scope: type StorageScope t = (Typeable t, SingI t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t)
+ Michelson.Typed.Scope: type UnpackedValScope t = (PackedValScope t, ConstantScope t)
+ Michelson.Typed.Scope: type family FailOnOperationFound (enabled :: Bool) :: Constraint
+ Michelson.Typed.Scope: withDict :: HasDict c e => e -> (c -> r) -> r
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI 'Michelson.Typed.T.TChainId
+ Michelson.Typed.T: TChainId :: T
+ Michelson.Typed.T: buildStack :: [T] -> Builder
+ Michelson.Typed.T: instance Formatting.Buildable.Buildable Michelson.Typed.T.T
+ Michelson.Typed.T: toUType :: T -> Type
+ Michelson.Typed.Util: CtorEffectsApp :: Text -> (forall i o. Semigroup x => x -> x -> Instr i o -> (Instr i o, x)) -> CtorEffectsApp x
+ Michelson.Typed.Util: DfsSettings :: Bool -> CtorEffectsApp x -> DfsSettings x
+ Michelson.Typed.Util: [ceaApplyEffects] :: CtorEffectsApp x -> forall i o. Semigroup x => x -> x -> Instr i o -> (Instr i o, x)
+ Michelson.Typed.Util: [ceaName] :: CtorEffectsApp x -> Text
+ Michelson.Typed.Util: [dsCtorEffectsApp] :: DfsSettings x -> CtorEffectsApp x
+ Michelson.Typed.Util: [dsGoToValues] :: DfsSettings x -> Bool
+ Michelson.Typed.Util: allAtomicValues :: forall t a. (forall t'. Value t' -> Maybe a) -> Value t -> [a]
+ Michelson.Typed.Util: data CtorEffectsApp x
+ Michelson.Typed.Util: data DfsSettings x
+ Michelson.Typed.Util: dfsFoldInstr :: forall x inp out. Semigroup x => DfsSettings x -> (forall i o. Instr i o -> x) -> Instr inp out -> x
+ Michelson.Typed.Util: dfsInstr :: forall x inp out. Semigroup x => DfsSettings x -> (forall i o. Instr i o -> (Instr i o, x)) -> Instr inp out -> (Instr inp out, x)
+ Michelson.Typed.Util: dfsModifyInstr :: DfsSettings () -> (forall i o. Instr i o -> Instr i o) -> Instr inp out -> Instr inp out
+ Michelson.Typed.Util: instance Data.Default.Class.Default (Michelson.Typed.Util.DfsSettings x)
+ Michelson.Typed.Util: instance GHC.Show.Show (Michelson.Typed.Util.CtorEffectsApp x)
+ Michelson.Typed.Util: instance GHC.Show.Show (Michelson.Typed.Util.DfsSettings x)
+ Michelson.Typed.Util: isBytesValue :: Value t -> Maybe ByteString
+ Michelson.Typed.Util: isStringValue :: Value t -> Maybe MText
+ Michelson.Typed.Util: linearizeLeft :: Instr inp out -> Instr inp out
+ Michelson.Typed.Value: [RfAlwaysFails] :: (forall o'. instr i o') -> RemFail instr i o
+ Michelson.Typed.Value: [RfNormal] :: instr i o -> RemFail instr i o
+ Michelson.Typed.Value: [SomeConstrainedValue] :: forall (t :: T) (c :: T -> Constraint) instr. c t => Value' instr t -> SomeConstrainedValue' instr c
+ Michelson.Typed.Value: [SomeValue] :: (Typeable t, SingI t) => Value' instr t -> SomeValue' instr
+ Michelson.Typed.Value: [VChainId] :: ChainId -> Value' instr 'TChainId
+ Michelson.Typed.Value: [ccOriginator] :: CreateContract instr cp st -> !Address
+ Michelson.Typed.Value: [ttTransferArgument] :: TransferTokens instr p -> !Value' instr p
+ Michelson.Typed.Value: addressToVContract :: forall t instr. ParameterScope t => Address -> Value' instr ( 'TContract t)
+ Michelson.Typed.Value: buildVContract :: Value' instr ( 'TContract arg) -> Builder
+ Michelson.Typed.Value: compileEpLiftSequence :: EpLiftSequence arg param -> Value' instr arg -> Value' instr param
+ Michelson.Typed.Value: data RemFail (instr :: k -> k -> Type) (i :: k) (o :: k)
+ Michelson.Typed.Value: data SomeConstrainedValue' instr (c :: T -> Constraint)
+ Michelson.Typed.Value: data SomeValue' instr
+ Michelson.Typed.Value: instance GHC.Classes.Eq (Michelson.Typed.Value.SomeValue' instr)
+ Michelson.Typed.Value: instance GHC.Show.Show (Michelson.Typed.Value.SomeConstrainedValue' instr c)
+ Michelson.Typed.Value: instance GHC.Show.Show (Michelson.Typed.Value.SomeValue' instr)
+ Michelson.Typed.Value: instance forall k (instr :: k -> k -> *) (i :: k) (o :: k). (forall (o' :: k). GHC.Show.Show (instr i o')) => GHC.Show.Show (Michelson.Typed.Value.RemFail instr i o)
+ Michelson.Typed.Value: instance forall k (instr :: k -> k -> *) (i :: k) (o :: k). GHC.Classes.Eq (instr i o) => GHC.Classes.Eq (Michelson.Typed.Value.RemFail instr i o)
+ Michelson.Typed.Value: rfAnyInstr :: RemFail instr i o -> instr i o
+ Michelson.Typed.Value: rfMapAnyInstr :: (forall o'. instr i1 o' -> instr i2 o') -> RemFail instr i1 o -> RemFail instr i2 o
+ Michelson.Typed.Value: rfMerge :: (forall o'. instr i1 o' -> instr i2 o' -> instr i3 o') -> RemFail instr i1 o -> RemFail instr i2 o -> RemFail instr i3 o
+ Michelson.Untyped.Annotation: instance Michelson.Untyped.Annotation.KnownAnnTag Michelson.Untyped.Annotation.FieldTag
+ Michelson.Untyped.Annotation: instance Michelson.Untyped.Annotation.KnownAnnTag Michelson.Untyped.Annotation.TypeTag
+ Michelson.Untyped.Annotation: instance Michelson.Untyped.Annotation.KnownAnnTag Michelson.Untyped.Annotation.VarTag
+ Michelson.Untyped.Annotation: instance forall k (tag :: k). Michelson.Untyped.Annotation.KnownAnnTag tag => Formatting.Buildable.Buildable (Michelson.Untyped.Annotation.Annotation tag)
+ Michelson.Untyped.Annotation: instance forall k (tag :: k). Michelson.Untyped.Annotation.KnownAnnTag tag => GHC.Show.Show (Michelson.Untyped.Annotation.Annotation tag)
+ Michelson.Untyped.Annotation: instance forall k (tag :: k). Michelson.Untyped.Annotation.KnownAnnTag tag => Michelson.Printer.Util.RenderDoc (Michelson.Untyped.Annotation.Annotation tag)
+ Michelson.Untyped.Annotation: renderWEAnn :: forall tag. KnownAnnTag tag => Annotation tag -> Doc
+ Michelson.Untyped.Annotation: type SomeAnn = Annotation SomeTag
+ Michelson.Untyped.Instr: APPLY :: VarAnn -> InstrAbstract op
+ Michelson.Untyped.Instr: CHAIN_ID :: VarAnn -> InstrAbstract op
+ Michelson.Untyped.Instr: DIG :: Word -> InstrAbstract op
+ Michelson.Untyped.Instr: DIPN :: Word -> [op] -> InstrAbstract op
+ Michelson.Untyped.Instr: DROPN :: Word -> InstrAbstract op
+ Michelson.Untyped.Instr: DUG :: Word -> InstrAbstract op
+ Michelson.Untyped.Instr: EMPTY_BIG_MAP :: TypeAnn -> VarAnn -> Comparable -> Type -> InstrAbstract op
+ Michelson.Untyped.Instr: [ooOriginator] :: OriginationOperation -> !Address
+ Michelson.Untyped.Type: TChainId :: T
+ Michelson.Untyped.Type: instance Michelson.Printer.Util.RenderDoc (Michelson.Printer.Util.Prettier Michelson.Untyped.Type.Type)
+ Michelson.Untyped.Type: toption :: Type -> T
+ Michelson.Untyped.Type: tor :: Type -> Type -> T
+ Michelson.Untyped.Type: tpair :: Type -> Type -> T
+ Michelson.Untyped.Type: tyImplicitAccountParam :: Type
+ Michelson.Untyped.Type: tybool :: Type
+ Michelson.Untyped.Type: tyint :: Type
+ Michelson.Untyped.Type: tynat :: Type
+ Michelson.Untyped.Type: tyor :: Type -> Type -> Type
+ Michelson.Untyped.Type: typair :: Type -> Type -> Type
+ Michelson.Untyped.Type: tyunit :: Type
+ Tezos.Address: ContractHash :: ByteString -> ContractHash
+ Tezos.Address: ParseAddressBothFailed :: !CryptoParseError -> !ParseContractAddressError -> ParseAddressError
+ Tezos.Address: ParseAddressWrongBase58Check :: ParseAddressError
+ Tezos.Address: data ParseAddressError
+ Tezos.Address: data ParseContractAddressError
+ Tezos.Address: detGenKeyAddress :: ByteString -> Address
+ Tezos.Address: instance Data.Aeson.Types.FromJSON.FromJSON Tezos.Address.ContractHash
+ Tezos.Address: instance Data.Aeson.Types.FromJSON.FromJSONKey Tezos.Address.ContractHash
+ Tezos.Address: instance Data.Aeson.Types.ToJSON.ToJSON Tezos.Address.ContractHash
+ Tezos.Address: instance Data.Aeson.Types.ToJSON.ToJSONKey Tezos.Address.ContractHash
+ Tezos.Address: instance GHC.Classes.Eq Tezos.Address.ContractHash
+ Tezos.Address: instance GHC.Classes.Ord Tezos.Address.ContractHash
+ Tezos.Address: instance GHC.Show.Show Tezos.Address.ContractHash
+ Tezos.Address: mkContractHashRaw :: ByteString -> ContractHash
+ Tezos.Address: newtype ContractHash
+ Tezos.Address: unsafeParseContractHash :: HasCallStack => Text -> ContractHash
+ Tezos.Core: ChainIdUnsafe :: ByteString -> ChainId
+ Tezos.Core: [unChainId] :: ChainId -> ByteString
+ Tezos.Core: chainIdLength :: Int
+ Tezos.Core: dummyChainId :: ChainId
+ Tezos.Core: farFuture :: Timestamp
+ Tezos.Core: farPast :: Timestamp
+ Tezos.Core: formatChainId :: ChainId -> Text
+ Tezos.Core: instance Data.Aeson.Types.FromJSON.FromJSON Tezos.Core.ChainId
+ Tezos.Core: instance Data.Aeson.Types.ToJSON.ToJSON Tezos.Core.ChainId
+ Tezos.Core: instance Formatting.Buildable.Buildable Tezos.Core.ChainId
+ Tezos.Core: instance Formatting.Buildable.Buildable Tezos.Core.ParseChainIdError
+ Tezos.Core: instance GHC.Classes.Eq Tezos.Core.ChainId
+ Tezos.Core: instance GHC.Classes.Eq Tezos.Core.ParseChainIdError
+ Tezos.Core: instance GHC.Show.Show Tezos.Core.ChainId
+ Tezos.Core: instance GHC.Show.Show Tezos.Core.ParseChainIdError
+ Tezos.Core: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Core.ChainId
+ Tezos.Core: mformatChainId :: ChainId -> MText
+ Tezos.Core: mkChainId :: ByteString -> Maybe ChainId
+ Tezos.Core: mkChainIdUnsafe :: HasCallStack => ByteString -> ChainId
+ Tezos.Core: newtype ChainId
+ Tezos.Core: parseChainId :: Text -> Either ParseChainIdError ChainId
+ Tezos.Core: timestampQuote :: QuasiQuoter
+ Tezos.Crypto: CryptoParseUnexpectedLength :: !Builder -> !Int -> CryptoParseError
+ Tezos.Crypto: KeyHashEd25519 :: KeyHashTag
+ Tezos.Crypto: KeyHashP256 :: KeyHashTag
+ Tezos.Crypto: KeyHashSecp256k1 :: KeyHashTag
+ Tezos.Crypto: PublicKeyEd25519 :: !PublicKey -> PublicKey
+ Tezos.Crypto: PublicKeyP256 :: !PublicKey -> PublicKey
+ Tezos.Crypto: PublicKeySecp256k1 :: !PublicKey -> PublicKey
+ Tezos.Crypto: SignatureEd25519 :: !Signature -> Signature
+ Tezos.Crypto: SignatureGeneric :: !ByteString -> Signature
+ Tezos.Crypto: SignatureP256 :: Signature -> Signature
+ Tezos.Crypto: SignatureSecp256k1 :: !Signature -> Signature
+ Tezos.Crypto: [khBytes] :: KeyHash -> ByteString
+ Tezos.Crypto: [khTag] :: KeyHash -> KeyHashTag
+ Tezos.Crypto: data KeyHash
+ Tezos.Crypto: data KeyHashTag
+ Tezos.Crypto: data PublicKey
+ Tezos.Crypto: data Signature
+ Tezos.Crypto: instance GHC.Classes.Eq Tezos.Crypto.KeyHashTag
+ Tezos.Crypto: instance GHC.Classes.Ord Tezos.Crypto.KeyHashTag
+ Tezos.Crypto: instance GHC.Enum.Bounded Tezos.Crypto.KeyHashTag
+ Tezos.Crypto: instance GHC.Enum.Enum Tezos.Crypto.KeyHashTag
+ Tezos.Crypto: instance GHC.Show.Show Tezos.Crypto.KeyHashTag
+ Tezos.Crypto: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Crypto.KeyHashTag
+ Tezos.Crypto: keyHashLengthBytes :: Integral n => n
+ Tezos.Crypto: signatureLengthBytes :: HasCallStack => Integral n => n
+ Tezos.Crypto: signatureToBytes :: ByteArray ba => Signature -> ba
+ Tezos.Crypto.Ed25519: PublicKey :: PublicKey -> PublicKey
+ Tezos.Crypto.Ed25519: Signature :: Signature -> Signature
+ Tezos.Crypto.Ed25519: [unPublicKey] :: PublicKey -> PublicKey
+ Tezos.Crypto.Ed25519: [unSignature] :: Signature -> Signature
+ Tezos.Crypto.Ed25519: checkSignature :: PublicKey -> Signature -> ByteString -> Bool
+ Tezos.Crypto.Ed25519: data SecretKey
+ Tezos.Crypto.Ed25519: detSecretKey :: ByteString -> SecretKey
+ Tezos.Crypto.Ed25519: formatPublicKey :: PublicKey -> Text
+ Tezos.Crypto.Ed25519: formatSecretKey :: SecretKey -> Text
+ Tezos.Crypto.Ed25519: formatSignature :: Signature -> Text
+ Tezos.Crypto.Ed25519: instance Formatting.Buildable.Buildable Tezos.Crypto.Ed25519.PublicKey
+ Tezos.Crypto.Ed25519: instance Formatting.Buildable.Buildable Tezos.Crypto.Ed25519.SecretKey
+ Tezos.Crypto.Ed25519: instance Formatting.Buildable.Buildable Tezos.Crypto.Ed25519.Signature
+ Tezos.Crypto.Ed25519: instance GHC.Classes.Eq Tezos.Crypto.Ed25519.PublicKey
+ Tezos.Crypto.Ed25519: instance GHC.Classes.Eq Tezos.Crypto.Ed25519.SecretKey
+ Tezos.Crypto.Ed25519: instance GHC.Classes.Eq Tezos.Crypto.Ed25519.Signature
+ Tezos.Crypto.Ed25519: instance GHC.Show.Show Tezos.Crypto.Ed25519.PublicKey
+ Tezos.Crypto.Ed25519: instance GHC.Show.Show Tezos.Crypto.Ed25519.SecretKey
+ Tezos.Crypto.Ed25519: instance GHC.Show.Show Tezos.Crypto.Ed25519.Signature
+ Tezos.Crypto.Ed25519: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Crypto.Ed25519.PublicKey
+ Tezos.Crypto.Ed25519: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Crypto.Ed25519.SecretKey
+ Tezos.Crypto.Ed25519: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Crypto.Ed25519.Signature
+ Tezos.Crypto.Ed25519: mformatPublicKey :: PublicKey -> MText
+ Tezos.Crypto.Ed25519: mformatSignature :: Signature -> MText
+ Tezos.Crypto.Ed25519: mkPublicKey :: ByteArrayAccess ba => ba -> Either CryptoParseError PublicKey
+ Tezos.Crypto.Ed25519: mkSignature :: ByteArrayAccess ba => ba -> Either CryptoParseError Signature
+ Tezos.Crypto.Ed25519: newtype PublicKey
+ Tezos.Crypto.Ed25519: newtype Signature
+ Tezos.Crypto.Ed25519: parsePublicKey :: Text -> Either CryptoParseError PublicKey
+ Tezos.Crypto.Ed25519: parseSignature :: Text -> Either CryptoParseError Signature
+ Tezos.Crypto.Ed25519: publicKeyLengthBytes :: Integral n => n
+ Tezos.Crypto.Ed25519: publicKeyToBytes :: ByteArray ba => PublicKey -> ba
+ Tezos.Crypto.Ed25519: sign :: SecretKey -> ByteString -> Signature
+ Tezos.Crypto.Ed25519: signatureLengthBytes :: Integral n => n
+ Tezos.Crypto.Ed25519: signatureToBytes :: ByteArray ba => Signature -> ba
+ Tezos.Crypto.Ed25519: toPublic :: SecretKey -> PublicKey
+ Tezos.Crypto.Hash: blake2b :: ByteString -> ByteString
+ Tezos.Crypto.Hash: blake2b160 :: ByteString -> ByteString
+ Tezos.Crypto.Hash: sha256 :: ByteString -> ByteString
+ Tezos.Crypto.Hash: sha512 :: ByteString -> ByteString
+ Tezos.Crypto.P256: PublicKey :: ByteString -> PublicKey
+ Tezos.Crypto.P256: Signature :: ByteString -> Signature
+ Tezos.Crypto.P256: [unPublicKey] :: PublicKey -> ByteString
+ Tezos.Crypto.P256: [unSignature] :: Signature -> ByteString
+ Tezos.Crypto.P256: checkSignature :: PublicKey -> Signature -> ByteString -> Bool
+ Tezos.Crypto.P256: data SecretKey
+ Tezos.Crypto.P256: detSecretKey :: ByteString -> SecretKey
+ Tezos.Crypto.P256: formatPublicKey :: PublicKey -> Text
+ Tezos.Crypto.P256: formatSignature :: Signature -> Text
+ Tezos.Crypto.P256: instance Formatting.Buildable.Buildable Tezos.Crypto.P256.PublicKey
+ Tezos.Crypto.P256: instance Formatting.Buildable.Buildable Tezos.Crypto.P256.Signature
+ Tezos.Crypto.P256: instance GHC.Classes.Eq Tezos.Crypto.P256.PublicKey
+ Tezos.Crypto.P256: instance GHC.Classes.Eq Tezos.Crypto.P256.SecretKey
+ Tezos.Crypto.P256: instance GHC.Classes.Eq Tezos.Crypto.P256.Signature
+ Tezos.Crypto.P256: instance GHC.Show.Show Tezos.Crypto.P256.PublicKey
+ Tezos.Crypto.P256: instance GHC.Show.Show Tezos.Crypto.P256.SecretKey
+ Tezos.Crypto.P256: instance GHC.Show.Show Tezos.Crypto.P256.Signature
+ Tezos.Crypto.P256: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Crypto.P256.PublicKey
+ Tezos.Crypto.P256: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Crypto.P256.SecretKey
+ Tezos.Crypto.P256: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Crypto.P256.Signature
+ Tezos.Crypto.P256: mformatPublicKey :: PublicKey -> MText
+ Tezos.Crypto.P256: mformatSignature :: Signature -> MText
+ Tezos.Crypto.P256: mkPublicKey :: ByteArrayAccess ba => ba -> Either CryptoParseError PublicKey
+ Tezos.Crypto.P256: mkSignature :: ByteArray ba => ba -> Either CryptoParseError Signature
+ Tezos.Crypto.P256: newtype PublicKey
+ Tezos.Crypto.P256: newtype Signature
+ Tezos.Crypto.P256: parsePublicKey :: Text -> Either CryptoParseError PublicKey
+ Tezos.Crypto.P256: parseSignature :: Text -> Either CryptoParseError Signature
+ Tezos.Crypto.P256: publicKeyLengthBytes :: Integral n => n
+ Tezos.Crypto.P256: publicKeyToBytes :: forall ba. ByteArray ba => PublicKey -> ba
+ Tezos.Crypto.P256: signatureLengthBytes :: Integral n => n
+ Tezos.Crypto.P256: signatureToBytes :: ByteArray ba => Signature -> ba
+ Tezos.Crypto.P256: toPublic :: SecretKey -> PublicKey
+ Tezos.Crypto.Secp256k1: PublicKey :: PublicKey -> !Maybe ByteString -> PublicKey
+ Tezos.Crypto.Secp256k1: Signature :: Signature -> Signature
+ Tezos.Crypto.Secp256k1: [pkBytes] :: PublicKey -> !Maybe ByteString
+ Tezos.Crypto.Secp256k1: [unPublicKey] :: PublicKey -> PublicKey
+ Tezos.Crypto.Secp256k1: [unSignature] :: Signature -> Signature
+ Tezos.Crypto.Secp256k1: checkSignature :: PublicKey -> Signature -> ByteString -> Bool
+ Tezos.Crypto.Secp256k1: data PublicKey
+ Tezos.Crypto.Secp256k1: data SecretKey
+ Tezos.Crypto.Secp256k1: detSecretKey :: ByteString -> SecretKey
+ Tezos.Crypto.Secp256k1: formatPublicKey :: PublicKey -> Text
+ Tezos.Crypto.Secp256k1: formatSignature :: Signature -> Text
+ Tezos.Crypto.Secp256k1: instance Formatting.Buildable.Buildable Tezos.Crypto.Secp256k1.PublicKey
+ Tezos.Crypto.Secp256k1: instance Formatting.Buildable.Buildable Tezos.Crypto.Secp256k1.Signature
+ Tezos.Crypto.Secp256k1: instance GHC.Classes.Eq Tezos.Crypto.Secp256k1.PublicKey
+ Tezos.Crypto.Secp256k1: instance GHC.Classes.Eq Tezos.Crypto.Secp256k1.SecretKey
+ Tezos.Crypto.Secp256k1: instance GHC.Classes.Eq Tezos.Crypto.Secp256k1.Signature
+ Tezos.Crypto.Secp256k1: instance GHC.Show.Show Tezos.Crypto.Secp256k1.PublicKey
+ Tezos.Crypto.Secp256k1: instance GHC.Show.Show Tezos.Crypto.Secp256k1.SecretKey
+ Tezos.Crypto.Secp256k1: instance GHC.Show.Show Tezos.Crypto.Secp256k1.Signature
+ Tezos.Crypto.Secp256k1: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Crypto.Secp256k1.PublicKey
+ Tezos.Crypto.Secp256k1: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Crypto.Secp256k1.SecretKey
+ Tezos.Crypto.Secp256k1: instance Test.QuickCheck.Arbitrary.Arbitrary Tezos.Crypto.Secp256k1.Signature
+ Tezos.Crypto.Secp256k1: mformatPublicKey :: PublicKey -> MText
+ Tezos.Crypto.Secp256k1: mformatSignature :: Signature -> MText
+ Tezos.Crypto.Secp256k1: mkPublicKey :: ByteArrayAccess ba => ba -> Either CryptoParseError PublicKey
+ Tezos.Crypto.Secp256k1: mkSignature :: ByteArray ba => ba -> Either CryptoParseError Signature
+ Tezos.Crypto.Secp256k1: newtype Signature
+ Tezos.Crypto.Secp256k1: parsePublicKey :: Text -> Either CryptoParseError PublicKey
+ Tezos.Crypto.Secp256k1: parseSignature :: Text -> Either CryptoParseError Signature
+ Tezos.Crypto.Secp256k1: publicKeyLengthBytes :: Integral n => n
+ Tezos.Crypto.Secp256k1: publicKeyToBytes :: forall ba. ByteArray ba => PublicKey -> ba
+ Tezos.Crypto.Secp256k1: sign :: MonadRandom m => SecretKey -> ByteString -> m Signature
+ Tezos.Crypto.Secp256k1: signatureLengthBytes :: Integral n => n
+ Tezos.Crypto.Secp256k1: signatureToBytes :: ByteArray ba => Signature -> ba
+ Tezos.Crypto.Secp256k1: toPublic :: SecretKey -> PublicKey
+ Tezos.Crypto.Util: B58CheckWithPrefixWrongEncoding :: B58CheckWithPrefixError
+ Tezos.Crypto.Util: B58CheckWithPrefixWrongPrefix :: ByteString -> B58CheckWithPrefixError
+ Tezos.Crypto.Util: CryptoParseCryptoError :: !CryptoError -> CryptoParseError
+ Tezos.Crypto.Util: CryptoParseUnexpectedLength :: !Builder -> !Int -> CryptoParseError
+ Tezos.Crypto.Util: CryptoParseWrongBase58Check :: CryptoParseError
+ Tezos.Crypto.Util: CryptoParseWrongTag :: !ByteString -> CryptoParseError
+ Tezos.Crypto.Util: data B58CheckWithPrefixError
+ Tezos.Crypto.Util: data CryptoParseError
+ Tezos.Crypto.Util: decodeBase58Check :: Text -> Maybe ByteString
+ Tezos.Crypto.Util: decodeBase58CheckWithPrefix :: ByteString -> Text -> Either B58CheckWithPrefixError ByteString
+ Tezos.Crypto.Util: deterministic :: ByteString -> MonadPseudoRandom ChaChaDRG a -> a
+ Tezos.Crypto.Util: encodeBase58Check :: ByteString -> Text
+ Tezos.Crypto.Util: firstRight :: NonEmpty (Either e a) -> Either e a
+ Tezos.Crypto.Util: formatImpl :: ByteArrayAccess x => ByteString -> x -> Text
+ Tezos.Crypto.Util: instance Formatting.Buildable.Buildable Tezos.Crypto.Util.CryptoParseError
+ Tezos.Crypto.Util: instance GHC.Classes.Eq Tezos.Crypto.Util.CryptoParseError
+ Tezos.Crypto.Util: instance GHC.Show.Show Tezos.Crypto.Util.B58CheckWithPrefixError
+ Tezos.Crypto.Util: instance GHC.Show.Show Tezos.Crypto.Util.CryptoParseError
+ Tezos.Crypto.Util: parseImpl :: ByteString -> (ByteString -> Either CryptoParseError res) -> Text -> Either CryptoParseError res
+ Util.Generic: type GenericTypeName a = GTypeName (Rep a)
+ Util.IO: appendFileUtf8 :: Print text => FilePath -> text -> IO ()
+ Util.Instances: instance Formatting.Buildable.Buildable a => Formatting.Buildable.Buildable (Data.Functor.Identity.Identity a)
+ Util.Lens: makeLensesWith :: LensRules -> Name -> DecsQ
+ Util.Lens: unwrappedP :: Wrapped a => Proxy a -> Proxy (Unwrapped a)
+ Util.Markdown: HeaderLevel :: Int -> HeaderLevel
+ Util.Markdown: md :: QuasiQuoter
+ Util.Markdown: mdAnchor :: Text -> Markdown
+ Util.Markdown: mdBold :: Markdown -> Markdown
+ Util.Markdown: mdComment :: Builder -> Builder
+ Util.Markdown: mdHeader :: HeaderLevel -> Markdown -> Markdown
+ Util.Markdown: mdItalic :: Markdown -> Markdown
+ Util.Markdown: mdLocalRef :: Markdown -> Text -> Markdown
+ Util.Markdown: mdRef :: Markdown -> Markdown -> Markdown
+ Util.Markdown: mdSeparator :: Markdown
+ Util.Markdown: mdSpoiler :: Markdown -> Markdown -> Markdown
+ Util.Markdown: mdSubsection :: Markdown -> Markdown -> Markdown
+ Util.Markdown: mdSubsectionTitle :: Markdown -> Markdown
+ Util.Markdown: mdTicked :: Markdown -> Markdown
+ Util.Markdown: newtype HeaderLevel
+ Util.Markdown: nextHeaderLevel :: HeaderLevel -> HeaderLevel
+ Util.Markdown: type Markdown = Builder
+ Util.Named: instance (Data.Typeable.Internal.Typeable f, Data.Typeable.Internal.Typeable a, GHC.TypeLits.KnownSymbol name, Data.Data.Data (f a)) => Data.Data.Data (Named.Internal.NamedF f a name)
+ Util.Named: instance (GHC.TypeLits.KnownSymbol name, Formatting.Buildable.Buildable (f a)) => Formatting.Buildable.Buildable (Named.Internal.NamedF f a name)
+ Util.Named: instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (Named.Internal.NamedF Data.Functor.Identity.Identity a name)
+ Util.Named: instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (Named.Internal.NamedF GHC.Maybe.Maybe a name)
+ Util.Named: instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Named.Internal.NamedF Data.Functor.Identity.Identity a name)
+ Util.Named: instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Named.Internal.NamedF GHC.Maybe.Maybe a name)
+ Util.Named: instance GHC.Classes.Eq (f a) => GHC.Classes.Eq (Named.Internal.NamedF f a name)
+ Util.Named: instance GHC.Classes.Ord (f a) => GHC.Classes.Ord (Named.Internal.NamedF f a name)
+ Util.Named: type (:?) (name :: Symbol) a = NamedF Maybe a name
+ Util.Peano: S :: !Nat -> Nat
+ Util.Peano: Z :: Nat
+ Util.Peano: class (RequireLongerOrSameLength' l a, LongerOrSameLength l a) => RequireLongerOrSameLength (l :: [k]) (a :: Peano)
+ Util.Peano: class (RequireLongerThan' l a, LongerThan l a) => RequireLongerThan (l :: [k]) (a :: Peano)
+ Util.Peano: data Nat
+ Util.Peano: instance (Data.Singletons.Internal.SingI n, Util.Peano.KnownPeano n) => Data.Singletons.Internal.SingI ('Data.Vinyl.TypeLevel.S n)
+ Util.Peano: instance GHC.Show.Show (Data.Singletons.Internal.Sing n)
+ Util.Peano: instance forall k (l :: [k]) (a :: Data.Vinyl.TypeLevel.Nat). (Util.Peano.RequireLongerThan' l a, Util.Peano.LongerThan l a) => Util.Peano.RequireLongerThan l a
+ Util.Peano: instance forall k (l :: [k]) (a :: Util.Peano.Peano). (Util.Peano.RequireLongerOrSameLength' l a, Util.Peano.LongerOrSameLength l a) => Util.Peano.RequireLongerOrSameLength l a
+ Util.Peano: peanoValSing :: forall n. KnownPeano n => Sing n -> Natural
+ Util.Peano: type LongerOrSameLength l a = IsLongerOrSameLength l a ~ 'True
+ Util.Positive: PositiveUnsafe :: Natural -> Positive
+ Util.Positive: [unPositive] :: Positive -> Natural
+ Util.Positive: instance Data.Aeson.Types.FromJSON.FromJSON Util.Positive.Positive
+ Util.Positive: instance Data.Aeson.Types.ToJSON.ToJSON Util.Positive.Positive
+ Util.Positive: instance Data.Data.Data Util.Positive.Positive
+ Util.Positive: instance Formatting.Buildable.Buildable Util.Positive.Positive
+ Util.Positive: instance GHC.Classes.Eq Util.Positive.Positive
+ Util.Positive: instance GHC.Classes.Ord Util.Positive.Positive
+ Util.Positive: instance GHC.Show.Show Util.Positive.Positive
+ Util.Positive: lengthNE :: NonEmpty a -> Positive
+ Util.Positive: mkPositive :: (Integral i, Buildable i) => i -> Either Text Positive
+ Util.Positive: newtype Positive
+ Util.Positive: replicateNE :: Positive -> a -> NonEmpty a
+ Util.Test.Arbitrary: instance (GHC.Classes.Ord k, Test.QuickCheck.Arbitrary.Arbitrary k, Test.QuickCheck.Arbitrary.Arbitrary v) => Test.QuickCheck.Arbitrary.Arbitrary (k Lorentz.UStore.Types.|~> v)
+ Util.Test.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary v => Test.QuickCheck.Arbitrary.Arbitrary (Lorentz.UStore.Types.UStoreFieldExt m v)
+ Util.Text: headToLower :: HasCallStack => Text -> Text
+ Util.Type: [KCons] :: KnownList xs => Proxy x -> Proxy xs -> KList (x : xs)
+ Util.Type: [KNil] :: KList '[]
+ Util.Type: class KnownList l
+ Util.Type: class ReifyList (c :: k -> Constraint) (l :: [k])
+ Util.Type: data KList (l :: [k])
+ Util.Type: infix 4 ==
+ Util.Type: instance Util.Type.KnownList '[]
+ Util.Type: instance forall a (c :: a -> GHC.Types.Constraint) (x :: a) (xs :: [a]). (c x, Util.Type.ReifyList c xs) => Util.Type.ReifyList c (x : xs)
+ Util.Type: instance forall k (c :: k -> GHC.Types.Constraint). Util.Type.ReifyList c '[]
+ Util.Type: instance forall k (xs :: [k]) (x :: k). Util.Type.KnownList xs => Util.Type.KnownList (x : xs)
+ Util.Type: klist :: KnownList l => KList l
+ Util.Type: reifyList :: ReifyList c l => (forall a. c a => Proxy a -> r) -> [r]
+ Util.Type: reifyTypeEquality :: forall a b x. (a == b) ~ 'True => (a ~ b => x) -> x
+ Util.Type: rsplit :: forall k (l :: [k]) (r :: [k]) f. RSplit l r => Rec f (l ++ r) -> (Rec f l, Rec f r)
+ Util.Type: type RSplit l r = KnownList l
+ Util.TypeLits: [:$$:] :: () => ErrorMessage -> ErrorMessage -> ErrorMessage
+ Util.TypeLits: [:<>:] :: () => ErrorMessage -> ErrorMessage -> ErrorMessage
+ Util.TypeLits: [ShowType] :: forall t. () => t -> ErrorMessage
+ Util.TypeLits: [Text] :: () => Symbol -> ErrorMessage
+ Util.TypeLits: class KnownSymbol (n :: Symbol)
+ Util.TypeLits: data ErrorMessage
+ Util.TypeLits: data Symbol
+ Util.TypeLits: inTypeErrorUnless :: forall cond err a. TypeErrorUnless cond err => (cond ~ 'True => a) -> a
+ Util.TypeLits: infixl 5 :$$:
+ Util.TypeLits: infixl 6 :<>:
+ Util.TypeLits: symbolValT :: forall s. KnownSymbol s => Proxy s -> Text
+ Util.TypeLits: symbolValT' :: forall s. KnownSymbol s => Text
+ Util.TypeLits: type family TypeErrorUnless (cond :: Bool) (err :: ErrorMessage) :: Constraint
+ Util.TypeTuple.Instances: instance forall u (f :: u -> *) (x1 :: u) (x2 :: u) (x3 :: u) (x4 :: u) (x5 :: u) (x6 :: u) (x7 :: u) (x8 :: u) (x9 :: u) (x10 :: u) (x11 :: u) (x12 :: u) (x13 :: u) (x14 :: u) (x15 :: u) (x16 :: u) (x17 :: u) (x18 :: u) (x19 :: u) (x20 :: u) (x21 :: u) (x22 :: u) (x23 :: u) (x24 :: u) (x25 :: u). Util.TypeTuple.Class.RecFromTuple (Data.Vinyl.Core.Rec f '[x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25])
+ Util.TypeTuple.Instances: instance forall u (f :: u -> *) (x1 :: u) (x2 :: u) (x3 :: u) (x4 :: u) (x5 :: u) (x6 :: u) (x7 :: u) (x8 :: u) (x9 :: u) (x10 :: u) (x11 :: u) (x12 :: u) (x13 :: u) (x14 :: u) (x15 :: u) (x16 :: u) (x17 :: u) (x18 :: u) (x19 :: u) (x20 :: u) (x21 :: u) (x22 :: u) (x23 :: u) (x24 :: u). Util.TypeTuple.Class.RecFromTuple (Data.Vinyl.Core.Rec f '[x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24])
+ Util.TypeTuple.Instances: instance forall u (f :: u -> *) (x1 :: u) (x2 :: u) (x3 :: u) (x4 :: u) (x5 :: u) (x6 :: u) (x7 :: u) (x8 :: u) (x9 :: u) (x10 :: u) (x11 :: u) (x12 :: u) (x13 :: u) (x14 :: u) (x15 :: u) (x16 :: u) (x17 :: u) (x18 :: u) (x19 :: u) (x20 :: u) (x21 :: u) (x22 :: u) (x23 :: u). Util.TypeTuple.Class.RecFromTuple (Data.Vinyl.Core.Rec f '[x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23])
+ Util.TypeTuple.Instances: instance forall u (f :: u -> *) (x1 :: u) (x2 :: u) (x3 :: u) (x4 :: u) (x5 :: u) (x6 :: u) (x7 :: u) (x8 :: u) (x9 :: u) (x10 :: u) (x11 :: u) (x12 :: u) (x13 :: u) (x14 :: u) (x15 :: u) (x16 :: u) (x17 :: u) (x18 :: u) (x19 :: u) (x20 :: u) (x21 :: u) (x22 :: u). Util.TypeTuple.Class.RecFromTuple (Data.Vinyl.Core.Rec f '[x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22])
+ Util.TypeTuple.Instances: instance forall u (f :: u -> *) (x1 :: u) (x2 :: u) (x3 :: u) (x4 :: u) (x5 :: u) (x6 :: u) (x7 :: u) (x8 :: u) (x9 :: u) (x10 :: u) (x11 :: u) (x12 :: u) (x13 :: u) (x14 :: u) (x15 :: u) (x16 :: u) (x17 :: u) (x18 :: u) (x19 :: u) (x20 :: u) (x21 :: u). Util.TypeTuple.Class.RecFromTuple (Data.Vinyl.Core.Rec f '[x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21])
+ Util.TypeTuple.Instances: instance forall u (f :: u -> *) (x1 :: u) (x2 :: u) (x3 :: u) (x4 :: u) (x5 :: u) (x6 :: u) (x7 :: u) (x8 :: u) (x9 :: u) (x10 :: u) (x11 :: u) (x12 :: u) (x13 :: u) (x14 :: u) (x15 :: u) (x16 :: u) (x17 :: u) (x18 :: u) (x19 :: u) (x20 :: u). Util.TypeTuple.Class.RecFromTuple (Data.Vinyl.Core.Rec f '[x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20])
+ Util.TypeTuple.Instances: instance forall u (f :: u -> *) (x1 :: u) (x2 :: u) (x3 :: u) (x4 :: u) (x5 :: u) (x6 :: u) (x7 :: u) (x8 :: u) (x9 :: u) (x10 :: u) (x11 :: u) (x12 :: u) (x13 :: u) (x14 :: u) (x15 :: u) (x16 :: u) (x17 :: u) (x18 :: u) (x19 :: u). Util.TypeTuple.Class.RecFromTuple (Data.Vinyl.Core.Rec f '[x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19])
+ Util.TypeTuple.Instances: instance forall u (f :: u -> *) (x1 :: u) (x2 :: u) (x3 :: u) (x4 :: u) (x5 :: u) (x6 :: u) (x7 :: u) (x8 :: u) (x9 :: u) (x10 :: u) (x11 :: u) (x12 :: u) (x13 :: u) (x14 :: u) (x15 :: u) (x16 :: u) (x17 :: u) (x18 :: u). Util.TypeTuple.Class.RecFromTuple (Data.Vinyl.Core.Rec f '[x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18])
+ Util.TypeTuple.Instances: instance forall u (f :: u -> *) (x1 :: u) (x2 :: u) (x3 :: u) (x4 :: u) (x5 :: u) (x6 :: u) (x7 :: u) (x8 :: u) (x9 :: u) (x10 :: u) (x11 :: u) (x12 :: u) (x13 :: u) (x14 :: u) (x15 :: u) (x16 :: u) (x17 :: u). Util.TypeTuple.Class.RecFromTuple (Data.Vinyl.Core.Rec f '[x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17])
+ Util.TypeTuple.Instances: instance forall u (f :: u -> *) (x1 :: u) (x2 :: u) (x3 :: u) (x4 :: u) (x5 :: u) (x6 :: u) (x7 :: u) (x8 :: u) (x9 :: u) (x10 :: u) (x11 :: u) (x12 :: u) (x13 :: u) (x14 :: u) (x15 :: u) (x16 :: u). Util.TypeTuple.Class.RecFromTuple (Data.Vinyl.Core.Rec f '[x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16])
+ Util.Typeable: compareExt :: forall a1 a2. (Typeable a1, Typeable a2, Ord a1) => a1 -> a2 -> Ordering
+ Util.Typeable: eqExt :: forall a1 a2. (Typeable a1, Typeable a2, Eq a1) => a1 -> a2 -> Bool
+ Util.Typeable: eqP :: (Typeable a, Typeable b) => Proxy a -> Proxy b -> Maybe (a :~: b)
+ Util.Typeable: eqParam1 :: forall a1 a2 t. (Typeable a1, Typeable a2, Eq (t a1)) => t a1 -> t a2 -> Bool
+ Util.Typeable: eqParam2 :: forall a1 a2 b1 b2 t. (Typeable a1, Typeable a2, Typeable b1, Typeable b2, Eq (t a1 b2)) => t a1 b1 -> t a2 b2 -> Bool
+ Util.Typeable: eqParam3 :: forall a1 a2 b1 b2 c1 c2 t. (Typeable a1, Typeable a2, Typeable b1, Typeable b2, Typeable c1, Typeable c2, Eq (t a1 b1 c1)) => t a1 b1 c1 -> t a2 b2 c2 -> Bool
+ Util.Typeable: gcastE :: forall a b t. (Typeable a, Typeable b) => t a -> Either Text (t b)
- Lorentz.ADT: (/->) :: Label ("c" `AppendSymbol` ctor) -> (AppendCtorField x inp :-> out) -> CaseClauseL inp out ( 'CaseClauseParam ctor x)
+ Lorentz.ADT: (/->) :: CaseArrow name body clause => Label name -> body -> clause
- Lorentz.ADT: caseT :: forall dt out inp clauses. (InstrCaseC dt inp out, RMap (CaseClauses dt), RecFromTuple clauses, clauses ~ Rec (CaseClauseL inp out) (CaseClauses dt)) => IsoRecTuple clauses -> (dt & inp) :-> out
+ Lorentz.ADT: caseT :: forall dt out inp clauses. CaseTC dt out inp clauses => IsoRecTuple clauses -> (dt & inp) :-> out
- Lorentz.ADT: fieldCtor :: (st :-> (f & st)) -> FieldConstructor st f
+ Lorentz.ADT: fieldCtor :: HasCallStack => (st :-> (f & st)) -> FieldConstructor st f
- Lorentz.Errors: type UserFailInstr e name s s' = (InstrWrapC e name, KnownSymbol name) => Label name -> AppendCtorField (GetCtorField e name) s :-> s'
+ Lorentz.Errors: type FailUsingArg e name fieldTy s s' = (KnownSymbol name, IsError e, IsoValue fieldTy, CtorHasOnlyField name e fieldTy, Each [Typeable, SingI] '[ToT fieldTy], HasCallStack) => Label name -> fieldTy : s :-> s'
- Lorentz.Ext: testAssert :: Typeable (ToTs out) => Text -> PrintComment (ToTs inp) -> (inp :-> (Bool & out)) -> inp :-> inp
+ Lorentz.Ext: testAssert :: (Typeable (ToTs out), HasCallStack) => Text -> PrintComment (ToTs inp) -> (inp :-> (Bool & out)) -> inp :-> inp
- Lorentz.Instr: address :: (ContractAddr a & s) :-> (Address & s)
+ Lorentz.Instr: address :: (ContractRef a & s) :-> (Address & s)
- Lorentz.Instr: compare :: ArithOpHs Compare n m => (n & (m & s)) :-> (ArithResHs Compare n m & s)
+ Lorentz.Instr: compare :: ArithOpHs Compare n n => (n & (n & s)) :-> (ArithResHs Compare n n & s)
- Lorentz.Instr: contract :: KnownValue p => (Address & s) :-> (Maybe (ContractAddr p) & s)
+ Lorentz.Instr: contract :: forall p s. NiceParameter p => (Address & s) :-> (Maybe (ContractRef p) & s)
- Lorentz.Instr: createContract :: forall p g s. (KnownValue p, NoOperation p, KnownValue g, NoOperation g, NoBigMap p, CanHaveBigMap g) => ('[(p, g)] :-> '[(List Operation, g)]) -> (KeyHash & (Maybe KeyHash & (Bool & (Bool & (Mutez & (g & s)))))) :-> (Operation & (Address & s))
+ Lorentz.Instr: createContract :: forall p g s. (NiceStorage g, ParameterEntryPoints p) => Contract p g -> (Maybe KeyHash & (Mutez & (g & s))) :-> (Operation & (Address & s))
- Lorentz.Instr: dip :: forall a s s'. (s :-> s') -> (a & s) :-> (a & s')
+ Lorentz.Instr: dip :: forall a s s'. HasCallStack => (s :-> s') -> (a & s) :-> (a & s')
- Lorentz.Instr: implicitAccount :: (KeyHash & s) :-> (ContractAddr () & s)
+ Lorentz.Instr: implicitAccount :: (KeyHash & s) :-> (ContractRef () & s)
- Lorentz.Instr: iter :: IterOpHs c => ((IterOpElHs c & s) :-> s) -> (c & s) :-> s
+ Lorentz.Instr: iter :: (IterOpHs c, HasCallStack) => ((IterOpElHs c & s) :-> s) -> (c & s) :-> s
- Lorentz.Instr: lambda :: (KnownValue i, KnownValue o) => Lambda i o -> s :-> (Lambda i o & s)
+ Lorentz.Instr: lambda :: (ZipInstrs [i, o], KnownValue (ZippedStack i), KnownValue (ZippedStack o)) => (i :-> o) -> s :-> ((i :-> o) & s)
- Lorentz.Instr: map :: (MapOpHs c, IsoMapOpRes c b) => ((MapOpInpHs c & s) :-> (b & s)) -> (c & s) :-> (MapOpResHs c b & s)
+ Lorentz.Instr: map :: (MapOpHs c, IsoMapOpRes c b, HasCallStack) => ((MapOpInpHs c & s) :-> (b & s)) -> (c & s) :-> (MapOpResHs c b & s)
- Lorentz.Instr: pack :: forall a s. (KnownValue a, NoOperation a, NoBigMap a) => (a & s) :-> (ByteString & s)
+ Lorentz.Instr: pack :: forall a s. NicePackedValue a => (a & s) :-> (ByteString & s)
- Lorentz.Instr: push :: forall t s. (KnownValue t, NoOperation t, NoBigMap t, IsoValue t) => t -> s :-> (t & s)
+ Lorentz.Instr: push :: forall t s. NiceConstant t => t -> s :-> (t & s)
- Lorentz.Instr: self :: forall cp s. s :-> (ContractAddr cp & s)
+ Lorentz.Instr: self :: forall p s. NiceParameter p => s :-> (ContractRef p & s)
- Lorentz.Instr: transferTokens :: forall p s. (KnownValue p, NoOperation p, NoBigMap p) => (p & (Mutez & (ContractAddr p & s))) :-> (Operation & s)
+ Lorentz.Instr: transferTokens :: forall p s. NiceParameter p => (p & (Mutez & (ContractRef p & s))) :-> (Operation & s)
- Lorentz.Instr: unpack :: forall a s. (KnownValue a, NoOperation a, NoBigMap a) => (ByteString & s) :-> (Maybe a & s)
+ Lorentz.Instr: unpack :: forall a s. NiceUnpackedValue a => (ByteString & s) :-> (Maybe a & s)
- Lorentz.Macro: View :: a -> ContractAddr (a, Maybe r) -> View
+ Lorentz.Macro: View :: a -> ContractRef r -> View
- Lorentz.Macro: [viewCallbackTo] :: View -> ContractAddr (a, Maybe r)
+ Lorentz.Macro: [viewCallbackTo] :: View -> ContractRef r
- Lorentz.Macro: assert :: MText -> (Bool & s) :-> s
+ Lorentz.Macro: assert :: IsError err => err -> (Bool & s) :-> s
- Lorentz.Macro: assertEq :: IfCmpXConstraints a b Eq' => MText -> (a & (b & s)) :-> s
+ Lorentz.Macro: assertEq :: (IfCmpXConstraints a Eq', IsError err) => err -> (a & (a & s)) :-> s
- Lorentz.Macro: assertEq0 :: IfCmp0Constraints a Eq' => MText -> (a & s) :-> s
+ Lorentz.Macro: assertEq0 :: (IfCmp0Constraints a Eq', IsError err) => err -> (a & s) :-> s
- Lorentz.Macro: assertGe :: IfCmpXConstraints a b Ge => MText -> (a & (b & s)) :-> s
+ Lorentz.Macro: assertGe :: (IfCmpXConstraints a Ge, IsError err) => err -> (a & (a & s)) :-> s
- Lorentz.Macro: assertGe0 :: IfCmp0Constraints a Ge => MText -> (a & s) :-> s
+ Lorentz.Macro: assertGe0 :: (IfCmp0Constraints a Ge, IsError err) => err -> (a & s) :-> s
- Lorentz.Macro: assertGt :: IfCmpXConstraints a b Gt => MText -> (a & (b & s)) :-> s
+ Lorentz.Macro: assertGt :: (IfCmpXConstraints a Gt, IsError err) => err -> (a & (a & s)) :-> s
- Lorentz.Macro: assertGt0 :: IfCmp0Constraints a Gt => MText -> (a & s) :-> s
+ Lorentz.Macro: assertGt0 :: (IfCmp0Constraints a Gt, IsError err) => err -> (a & s) :-> s
- Lorentz.Macro: assertLe :: IfCmpXConstraints a b Le => MText -> (a & (b & s)) :-> s
+ Lorentz.Macro: assertLe :: (IfCmpXConstraints a Le, IsError err) => err -> (a & (a & s)) :-> s
- Lorentz.Macro: assertLe0 :: IfCmp0Constraints a Le => MText -> (a & s) :-> s
+ Lorentz.Macro: assertLe0 :: (IfCmp0Constraints a Le, IsError err) => err -> (a & s) :-> s
- Lorentz.Macro: assertLeft :: MText -> (Either a b & s) :-> (a & s)
+ Lorentz.Macro: assertLeft :: IsError err => err -> (Either a b & s) :-> (a & s)
- Lorentz.Macro: assertLt :: IfCmpXConstraints a b Lt => MText -> (a & (b & s)) :-> s
+ Lorentz.Macro: assertLt :: (IfCmpXConstraints a Lt, IsError err) => err -> (a & (a & s)) :-> s
- Lorentz.Macro: assertLt0 :: IfCmp0Constraints a Lt => MText -> (a & s) :-> s
+ Lorentz.Macro: assertLt0 :: (IfCmp0Constraints a Lt, IsError err) => err -> (a & s) :-> s
- Lorentz.Macro: assertNeq :: IfCmpXConstraints a b Neq => MText -> (a & (b & s)) :-> s
+ Lorentz.Macro: assertNeq :: (IfCmpXConstraints a Neq, IsError err) => err -> (a & (a & s)) :-> s
- Lorentz.Macro: assertNeq0 :: IfCmp0Constraints a Neq => MText -> (a & s) :-> s
+ Lorentz.Macro: assertNeq0 :: (IfCmp0Constraints a Neq, IsError err) => err -> (a & s) :-> s
- Lorentz.Macro: assertNone :: MText -> (Maybe a & s) :-> s
+ Lorentz.Macro: assertNone :: IsError err => err -> (Maybe a & s) :-> s
- Lorentz.Macro: assertRight :: MText -> (Either a b & s) :-> (b & s)
+ Lorentz.Macro: assertRight :: IsError err => err -> (Either a b & s) :-> (b & s)
- Lorentz.Macro: assertSome :: MText -> (Maybe a & s) :-> (a & s)
+ Lorentz.Macro: assertSome :: IsError err => err -> (Maybe a & s) :-> (a & s)
- Lorentz.Macro: assertUsing :: (IsoValue a, KnownValue a, NoOperation a, NoBigMap a) => a -> (Bool & s) :-> s
+ Lorentz.Macro: assertUsing :: IsError a => a -> (Bool & s) :-> s
- Lorentz.Macro: dropX :: forall (n :: Nat) a inp out s s'. (DipX (ToPeano n) (Above (ToPeano n) inp) s s', (Above (ToPeano n) inp ++ s) ~ inp, (Above (ToPeano n) inp ++ s') ~ out, s ~ (a : s')) => inp :-> out
+ Lorentz.Macro: dropX :: forall (n :: Nat) a inp out s s'. (ConstraintDIPNLorentz (ToPeano n) inp out s s', s ~ (a : s')) => inp :-> out
- Lorentz.Macro: duupX :: forall (n :: Nat) inp. DuupX (ToPeano n) inp (At (ToPeano (n - 1)) inp) => inp :-> (At (ToPeano (n - 1)) inp & inp)
+ Lorentz.Macro: duupX :: forall (n :: Nat) a (s :: [Type]) (s1 :: [Type]) (tail :: [Type]). (ConstraintDuupXLorentz (ToPeano (n - 1)) s a s1 tail, DuupX (ToPeano n) s a s1 tail) => s :-> (a : s)
- Lorentz.Macro: eq :: (ArithOpHs Compare n m, UnaryArithOpHs Eq' (ArithResHs Compare n m)) => (n & (m & s)) :-> (UnaryArithResHs Eq' (ArithResHs Compare n m) & s)
+ Lorentz.Macro: eq :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Eq' (ArithResHs Compare n n) & s)
- Lorentz.Macro: ge :: (ArithOpHs Compare n m, UnaryArithOpHs Ge (ArithResHs Compare n m)) => (n & (m & s)) :-> (UnaryArithResHs Ge (ArithResHs Compare n m) & s)
+ Lorentz.Macro: ge :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Ge (ArithResHs Compare n n) & s)
- Lorentz.Macro: gt :: (ArithOpHs Compare n m, UnaryArithOpHs Gt (ArithResHs Compare n m)) => (n & (m & s)) :-> (UnaryArithResHs Gt (ArithResHs Compare n m) & s)
+ Lorentz.Macro: gt :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Gt (ArithResHs Compare n n) & s)
- Lorentz.Macro: ifEq :: IfCmpXConstraints a b Eq' => (s :-> s') -> (s :-> s') -> (a & (b & s)) :-> s'
+ Lorentz.Macro: ifEq :: IfCmpXConstraints a Eq' => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
- Lorentz.Macro: ifGe :: IfCmpXConstraints a b Ge => (s :-> s') -> (s :-> s') -> (a & (b & s)) :-> s'
+ Lorentz.Macro: ifGe :: IfCmpXConstraints a Ge => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
- Lorentz.Macro: ifGt :: IfCmpXConstraints a b Gt => (s :-> s') -> (s :-> s') -> (a & (b & s)) :-> s'
+ Lorentz.Macro: ifGt :: IfCmpXConstraints a Gt => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
- Lorentz.Macro: ifLe :: IfCmpXConstraints a b Le => (s :-> s') -> (s :-> s') -> (a & (b & s)) :-> s'
+ Lorentz.Macro: ifLe :: IfCmpXConstraints a Le => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
- Lorentz.Macro: ifLt :: IfCmpXConstraints a b Lt => (s :-> s') -> (s :-> s') -> (a & (b & s)) :-> s'
+ Lorentz.Macro: ifLt :: IfCmpXConstraints a Lt => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
- Lorentz.Macro: ifNeq :: IfCmpXConstraints a b Neq => (s :-> s') -> (s :-> s') -> (a & (b & s)) :-> s'
+ Lorentz.Macro: ifNeq :: IfCmpXConstraints a Neq => (s :-> s') -> (s :-> s') -> (a & (a & s)) :-> s'
- Lorentz.Macro: le :: (ArithOpHs Compare n m, UnaryArithOpHs Le (ArithResHs Compare n m)) => (n & (m & s)) :-> (UnaryArithResHs Le (ArithResHs Compare n m) & s)
+ Lorentz.Macro: le :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Le (ArithResHs Compare n n) & s)
- Lorentz.Macro: lt :: (ArithOpHs Compare n m, UnaryArithOpHs Lt (ArithResHs Compare n m)) => (n & (m & s)) :-> (UnaryArithResHs Lt (ArithResHs Compare n m) & s)
+ Lorentz.Macro: lt :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Lt (ArithResHs Compare n n) & s)
- Lorentz.Macro: neq :: (ArithOpHs Compare n m, UnaryArithOpHs Neq (ArithResHs Compare n m)) => (n & (m & s)) :-> (UnaryArithResHs Neq (ArithResHs Compare n m) & s)
+ Lorentz.Macro: neq :: ArithOpHs Compare n n => (n & (n & s)) :-> (UnaryArithResHs Neq (ArithResHs Compare n n) & s)
- Lorentz.Macro: type IfCmpXConstraints a b op = (Typeable a, Typeable b, ArithOpHs Compare a b, UnaryArithOpHs op (ArithResHs Compare a b), UnaryArithResHs op (ArithResHs Compare a b) ~ Bool)
+ Lorentz.Macro: type IfCmpXConstraints a op = (Typeable a, ArithOpHs Compare a a, UnaryArithOpHs op (ArithResHs Compare a a), UnaryArithResHs op (ArithResHs Compare a a) ~ Bool)
- Lorentz.Macro: view_ :: (KnownValue a, KnownValue r, NoOperation (a, r), NoBigMap (a, r)) => (forall s0. ((a, storage) & s0) :-> (r : s0)) -> (View a r & (storage & s)) :-> ((List Operation, storage) & s)
+ Lorentz.Macro: view_ :: NiceParameter r => (forall s0. ((a, storage) & s0) :-> (r : s0)) -> (View a r & (storage & s)) :-> ((List Operation, storage) & s)
- Lorentz.Macro: void_ :: forall a b s s' anything. KnownValue b => ((a & s) :-> (b & s')) -> (Void_ a b & s) :-> anything
+ Lorentz.Macro: void_ :: forall a b s s' anything. (IsError (VoidResult b), KnownValue b) => ((a & s) :-> (b & s')) -> (Void_ a b & s) :-> anything
- Lorentz.Rebinded: [IsEq] :: IfCmpXConstraints a b Eq' => Condition s (a : (b : s)) s s
+ Lorentz.Rebinded: [IsEq] :: IfCmpXConstraints a Eq' => Condition s (a : (a : s)) s s
- Lorentz.Rebinded: [IsGe] :: IfCmpXConstraints a b Ge => Condition s (a : (b : s)) s s
+ Lorentz.Rebinded: [IsGe] :: IfCmpXConstraints a Ge => Condition s (a : (a : s)) s s
- Lorentz.Rebinded: [IsGt] :: IfCmpXConstraints a b Gt => Condition s (a : (b : s)) s s
+ Lorentz.Rebinded: [IsGt] :: IfCmpXConstraints a Gt => Condition s (a : (a : s)) s s
- Lorentz.Rebinded: [IsLe] :: IfCmpXConstraints a b Le => Condition s (a : (b : s)) s s
+ Lorentz.Rebinded: [IsLe] :: IfCmpXConstraints a Le => Condition s (a : (a : s)) s s
- Lorentz.Rebinded: [IsLt] :: IfCmpXConstraints a b Lt => Condition s (a : (b : s)) s s
+ Lorentz.Rebinded: [IsLt] :: IfCmpXConstraints a Lt => Condition s (a : (a : s)) s s
- Lorentz.Rebinded: [IsNeq] :: IfCmpXConstraints a b Neq => Condition s (a : (b : s)) s s
+ Lorentz.Rebinded: [IsNeq] :: IfCmpXConstraints a Neq => Condition s (a : (a : s)) s s
- Lorentz.Store: storageInsertNew :: forall store name fields err s. (StoreInsertC store name, KnownSymbol name, KnownValue err) => Label name -> (forall s0. (GetStoreKey store name : s0) :-> (err : s0)) -> (GetStoreKey store name : (GetStoreValue store name : (StorageSkeleton store fields : s))) :-> (StorageSkeleton store fields : s)
+ Lorentz.Store: storageInsertNew :: forall store name fields s. (StoreInsertC store name, KnownSymbol name) => Label name -> (forall s0 any. (GetStoreKey store name : s0) :-> any) -> (GetStoreKey store name : (GetStoreValue store name : (StorageSkeleton store fields : s))) :-> (StorageSkeleton store fields : s)
- Lorentz.Store: storeInsertNew :: forall store name err s. (StoreInsertC store name, KnownSymbol name, KnownValue err) => Label name -> (forall s0. (GetStoreKey store name : s0) :-> (err : s0)) -> (GetStoreKey store name : (GetStoreValue store name : (Store store : s))) :-> (Store store : s)
+ Lorentz.Store: storeInsertNew :: forall store name s. (StoreInsertC store name, KnownSymbol name) => Label name -> (forall s0 any. (GetStoreKey store name : s0) :-> any) -> (GetStoreKey store name : (GetStoreValue store name : (Store store : s))) :-> (Store store : s)
- Lorentz.Store: storeLookup :: forall name store key value ctorIdx. (key ~ GetStoreKey store name, value ~ GetStoreValue store name, ctorIdx ~ MSCtorIdx (GetStore name store), IsoValue key, KnownValue key, HasNoOp (ToT key), HasNoBigMap (ToT key), KnownNat ctorIdx, InstrUnwrapC store name, Generic store, CtorOnlyField name store ~ (key |-> value)) => Label name -> key -> Store store -> Maybe value
+ Lorentz.Store: storeLookup :: forall name store key value ctorIdx. (key ~ GetStoreKey store name, value ~ GetStoreValue store name, ctorIdx ~ MSCtorIdx (GetStore name store), NicePackedValue key, KnownNat ctorIdx, InstrUnwrapC store name, Generic store, CtorOnlyField name store ~ (key |-> value)) => Label name -> key -> Store store -> Maybe value
- Lorentz.Store: type StoreDeleteC store name = (StoreOpC store name, SingI (ToT store))
+ Lorentz.Store: type StoreDeleteC store name = (StoreOpC store name, KnownValue store)
- Lorentz.Store: type StoreGetC store name = (StoreOpC store name, InstrUnwrapC store name, SingI (ToT (GetStoreValue store name)), CtorHasOnlyField name store (GetStoreKey store name |-> GetStoreValue store name))
+ Lorentz.Store: type StoreGetC store name = (StoreOpC store name, InstrUnwrapC store name, KnownValue (GetStoreValue store name), CtorHasOnlyField name store (GetStoreKey store name |-> GetStoreValue store name))
- Lorentz.Store: type StorePieceC store name key value = (key ~ GetStoreKey store name, value ~ GetStoreValue store name, IsoValue key, KnownValue key, HasNoOp (ToT key), HasNoBigMap (ToT key), KnownNat (MSCtorIdx (GetStore name store)), InstrWrapC store name, Generic store, ExtractCtorField (GetCtorField store name) ~ (key |-> value))
+ Lorentz.Store: type StorePieceC store name key value = (key ~ GetStoreKey store name, value ~ GetStoreValue store name, NicePackedValue key, KnownNat (MSCtorIdx (GetStore name store)), InstrWrapC store name, Generic store, ExtractCtorField (GetCtorField store name) ~ (key |-> value))
- Lorentz.Test: integrationalTestExpectation :: IntegrationalScenario -> Expectation
+ Lorentz.Test: integrationalTestExpectation :: HasCallStack => IntegrationalScenario -> Expectation
- Lorentz.Test: lCall :: (SingI (ToT cp), HasNoOp (ToT cp), IsoValue cp) => ContractAddr cp -> cp -> IntegrationalScenarioM ()
+ Lorentz.Test: lCall :: forall cp contract. (NiceParameter cp, ToContractRef cp contract) => contract -> cp -> IntegrationalScenarioM ()
- Lorentz.Test: lExpectBalance :: ContractAddr cp -> Mutez -> SuccessValidator
+ Lorentz.Test: lExpectBalance :: ToAddress addr => addr -> Mutez -> SuccessValidator
- Lorentz.Test: lExpectConsumerStorage :: (st ~ [cp], IsoValue st, Each [Typeable, SingI, HasNoOp] '[ToT st]) => ContractAddr cp -> (st -> Either ValidationError ()) -> SuccessValidator
+ Lorentz.Test: lExpectConsumerStorage :: forall cp st contract. (st ~ [cp], NiceStorage st, ToContractRef cp contract) => contract -> (st -> Either ValidationError ()) -> SuccessValidator
- Lorentz.Test: lExpectMichelsonFailed :: (MichelsonFailed -> Bool) -> ContractAddr cp -> InterpreterError -> Bool
+ Lorentz.Test: lExpectMichelsonFailed :: forall addr. ToAddress addr => (MichelsonFailed -> Bool) -> addr -> InterpreterError -> Bool
- Lorentz.Test: lExpectStorageConst :: (IsoValue st, Each '[SingI, HasNoOp] '[ToT st]) => ContractAddr cp -> st -> SuccessValidator
+ Lorentz.Test: lExpectStorageConst :: forall st addr. (NiceStorage st, ToAddress addr) => addr -> st -> SuccessValidator
- Lorentz.Test: lExpectStorageUpdate :: (IsoValue st, Each [Typeable, SingI, HasNoOp] '[ToT st], HasCallStack) => ContractAddr cp -> (st -> Either ValidationError ()) -> SuccessValidator
+ Lorentz.Test: lExpectStorageUpdate :: forall st addr. (NiceStorage st, ToAddress addr, HasCallStack) => addr -> (st -> Either ValidationError ()) -> SuccessValidator
- Lorentz.Test: lExpectViewConsumerStorage :: (st ~ [cp], cp ~ (arg, Maybe res), Eq res, Buildable res, IsoValue st, Each [Typeable, SingI, HasNoOp] '[ToT st]) => ContractAddr cp -> [res] -> SuccessValidator
+ Lorentz.Test: lExpectViewConsumerStorage :: (st ~ [cp], Eq cp, Buildable cp, NiceStorage st, ToContractRef cp contract) => contract -> [cp] -> SuccessValidator
- Lorentz.Test: lOriginate :: (SingI (ToT cp), SingI (ToT st), HasNoOp (ToT st), IsoValue st) => Contract cp st -> Text -> st -> Mutez -> IntegrationalScenarioM (ContractAddr cp)
+ Lorentz.Test: lOriginate :: forall cp st. (NiceParameter cp, NiceStorage st) => Contract cp st -> Text -> st -> Mutez -> IntegrationalScenarioM (ContractRef cp)
- Lorentz.Test: lOriginateEmpty :: (SingI (ToT cp), SingI (ToT st), HasNoOp (ToT st), IsoValue st, Default st) => Contract cp st -> Text -> IntegrationalScenarioM (ContractAddr cp)
+ Lorentz.Test: lOriginateEmpty :: (NiceParameter cp, NiceStorage st, Default st) => Contract cp st -> Text -> IntegrationalScenarioM (ContractRef cp)
- Lorentz.Test: lTransfer :: (SingI (ToT cp), HasNoOp (ToT cp), IsoValue cp) => ("from" :! Address) -> ("to" :! ContractAddr cp) -> Mutez -> cp -> IntegrationalScenarioM ()
+ Lorentz.Test: lTransfer :: forall cp contract. (NiceParameter cp, ToContractRef cp contract) => ("from" :! Address) -> ("to" :! contract) -> Mutez -> cp -> IntegrationalScenarioM ()
- Lorentz.Test: type IntegrationalScenarioM = StateT InternalState (Except ValidationError)
+ Lorentz.Test: type IntegrationalScenarioM = StateT InternalState (Except ScenarioError)
- Lorentz.Test: type SuccessValidator = (InternalState -> GState -> [GStateUpdate] -> Either ValidationError ())
+ Lorentz.Test: type SuccessValidator = InternalState -> GState -> [GStateUpdate] -> Either ValidationError ()
- Lorentz.Test.Integrational: integrationalTestExpectation :: IntegrationalScenario -> Expectation
+ Lorentz.Test.Integrational: integrationalTestExpectation :: HasCallStack => IntegrationalScenario -> Expectation
- Lorentz.Test.Integrational: lCall :: (SingI (ToT cp), HasNoOp (ToT cp), IsoValue cp) => ContractAddr cp -> cp -> IntegrationalScenarioM ()
+ Lorentz.Test.Integrational: lCall :: forall cp contract. (NiceParameter cp, ToContractRef cp contract) => contract -> cp -> IntegrationalScenarioM ()
- Lorentz.Test.Integrational: lExpectBalance :: ContractAddr cp -> Mutez -> SuccessValidator
+ Lorentz.Test.Integrational: lExpectBalance :: ToAddress addr => addr -> Mutez -> SuccessValidator
- Lorentz.Test.Integrational: lExpectConsumerStorage :: (st ~ [cp], IsoValue st, Each [Typeable, SingI, HasNoOp] '[ToT st]) => ContractAddr cp -> (st -> Either ValidationError ()) -> SuccessValidator
+ Lorentz.Test.Integrational: lExpectConsumerStorage :: forall cp st contract. (st ~ [cp], NiceStorage st, ToContractRef cp contract) => contract -> (st -> Either ValidationError ()) -> SuccessValidator
- Lorentz.Test.Integrational: lExpectMichelsonFailed :: (MichelsonFailed -> Bool) -> ContractAddr cp -> InterpreterError -> Bool
+ Lorentz.Test.Integrational: lExpectMichelsonFailed :: forall addr. ToAddress addr => (MichelsonFailed -> Bool) -> addr -> InterpreterError -> Bool
- Lorentz.Test.Integrational: lExpectStorageConst :: (IsoValue st, Each '[SingI, HasNoOp] '[ToT st]) => ContractAddr cp -> st -> SuccessValidator
+ Lorentz.Test.Integrational: lExpectStorageConst :: forall st addr. (NiceStorage st, ToAddress addr) => addr -> st -> SuccessValidator
- Lorentz.Test.Integrational: lExpectStorageUpdate :: (IsoValue st, Each [Typeable, SingI, HasNoOp] '[ToT st], HasCallStack) => ContractAddr cp -> (st -> Either ValidationError ()) -> SuccessValidator
+ Lorentz.Test.Integrational: lExpectStorageUpdate :: forall st addr. (NiceStorage st, ToAddress addr, HasCallStack) => addr -> (st -> Either ValidationError ()) -> SuccessValidator
- Lorentz.Test.Integrational: lExpectViewConsumerStorage :: (st ~ [cp], cp ~ (arg, Maybe res), Eq res, Buildable res, IsoValue st, Each [Typeable, SingI, HasNoOp] '[ToT st]) => ContractAddr cp -> [res] -> SuccessValidator
+ Lorentz.Test.Integrational: lExpectViewConsumerStorage :: (st ~ [cp], Eq cp, Buildable cp, NiceStorage st, ToContractRef cp contract) => contract -> [cp] -> SuccessValidator
- Lorentz.Test.Integrational: lOriginate :: (SingI (ToT cp), SingI (ToT st), HasNoOp (ToT st), IsoValue st) => Contract cp st -> Text -> st -> Mutez -> IntegrationalScenarioM (ContractAddr cp)
+ Lorentz.Test.Integrational: lOriginate :: forall cp st. (NiceParameter cp, NiceStorage st) => Contract cp st -> Text -> st -> Mutez -> IntegrationalScenarioM (ContractRef cp)
- Lorentz.Test.Integrational: lOriginateEmpty :: (SingI (ToT cp), SingI (ToT st), HasNoOp (ToT st), IsoValue st, Default st) => Contract cp st -> Text -> IntegrationalScenarioM (ContractAddr cp)
+ Lorentz.Test.Integrational: lOriginateEmpty :: (NiceParameter cp, NiceStorage st, Default st) => Contract cp st -> Text -> IntegrationalScenarioM (ContractRef cp)
- Lorentz.Test.Integrational: lTransfer :: (SingI (ToT cp), HasNoOp (ToT cp), IsoValue cp) => ("from" :! Address) -> ("to" :! ContractAddr cp) -> Mutez -> cp -> IntegrationalScenarioM ()
+ Lorentz.Test.Integrational: lTransfer :: forall cp contract. (NiceParameter cp, ToContractRef cp contract) => ("from" :! Address) -> ("to" :! contract) -> Mutez -> cp -> IntegrationalScenarioM ()
- Lorentz.Test.Integrational: type IntegrationalScenarioM = StateT InternalState (Except ValidationError)
+ Lorentz.Test.Integrational: type IntegrationalScenarioM = StateT InternalState (Except ScenarioError)
- Lorentz.Test.Integrational: type SuccessValidator = (InternalState -> GState -> [GStateUpdate] -> Either ValidationError ())
+ Lorentz.Test.Integrational: type SuccessValidator = InternalState -> GState -> [GStateUpdate] -> Either ValidationError ()
- Lorentz.Value: [CvAddress] :: Address -> CValue 'CAddress
+ Lorentz.Value: [CvAddress] :: EpAddress -> CValue 'CAddress
- Michelson.Interpret: ContractEnv :: !Timestamp -> !RemainingSteps -> !Mutez -> TcOriginatedContracts -> !Address -> !Address -> !Address -> !Mutez -> ContractEnv
+ Michelson.Interpret: ContractEnv :: !Timestamp -> !RemainingSteps -> !Mutez -> TcOriginatedContracts -> !Address -> !Address -> !Address -> !Mutez -> !ChainId -> ContractEnv
- Michelson.Interpret: IllTypedContract :: TCError -> InterpretUntypedError
+ Michelson.Interpret: IllTypedContract :: TCError -> InterpretError
- Michelson.Interpret: IllTypedParam :: TCError -> InterpretUntypedError
+ Michelson.Interpret: IllTypedParam :: TCError -> InterpretError
- Michelson.Interpret: IllTypedStorage :: TCError -> InterpretUntypedError
+ Michelson.Interpret: IllTypedStorage :: TCError -> InterpretError
- Michelson.Interpret: RuntimeFailure :: (MichelsonFailed, MorleyLogs) -> InterpretUntypedError
+ Michelson.Interpret: RuntimeFailure :: (MichelsonFailed, MorleyLogs) -> InterpretError
- Michelson.Interpret: UnexpectedParamType :: TCTypeError -> InterpretUntypedError
+ Michelson.Interpret: UnexpectedParamType :: TCTypeError -> InterpretError
- Michelson.Interpret: UnexpectedStorageType :: TCTypeError -> InterpretUntypedError
+ Michelson.Interpret: UnexpectedStorageType :: TCTypeError -> InterpretError
- Michelson.Interpret: interpretUntyped :: Contract -> Value -> Value -> ContractEnv -> Either InterpretUntypedError InterpretUntypedResult
+ Michelson.Interpret: interpretUntyped :: Contract -> Value -> Value -> ContractEnv -> Either InterpretError InterpretResult
- Michelson.Interpret: runUnpack :: forall t. (SingI t, HasNoOp t, HasNoBigMap t) => TcOriginatedContracts -> ByteString -> Either UnpackError (Value t)
+ Michelson.Interpret: runUnpack :: forall t. UnpackedValScope t => ByteString -> Either UnpackError (Value t)
- Michelson.Interpret.Pack: packValue :: (SingI t, HasNoOp t, HasNoBigMap t) => Value t -> LByteString
+ Michelson.Interpret.Pack: packValue :: PackedValScope t => Value t -> LByteString
- Michelson.Interpret.Pack: packValue' :: (SingI t, HasNoOp t, HasNoBigMap t) => Value t -> ByteString
+ Michelson.Interpret.Pack: packValue' :: PackedValScope t => Value t -> ByteString
- Michelson.Interpret.Unpack: unpackValue :: (SingI t, HasNoOp t, HasNoBigMap t) => UnpackEnv -> LByteString -> Either UnpackError (Value t)
+ Michelson.Interpret.Unpack: unpackValue :: UnpackedValScope t => LByteString -> Either UnpackError (Value t)
- Michelson.Interpret.Unpack: unpackValue' :: (SingI t, HasNoOp t, HasNoBigMap t) => UnpackEnv -> ByteString -> Either UnpackError (Value t)
+ Michelson.Interpret.Unpack: unpackValue' :: UnpackedValScope t => ByteString -> Either UnpackError (Value t)
- Michelson.Macro: DIIP :: Integer -> [ParsedOp] -> Macro
+ Michelson.Macro: DIIP :: Word -> [ParsedOp] -> Macro
- Michelson.Macro: DUUP :: Integer -> VarAnn -> Macro
+ Michelson.Macro: DUUP :: Word -> VarAnn -> Macro
- Michelson.Printer: printDoc :: Doc -> Text
+ Michelson.Printer: printDoc :: Bool -> Doc -> Text
- Michelson.Printer: printTypedContract :: (SingI p, SingI s) => Contract p s -> Text
+ Michelson.Printer: printTypedContract :: (SingI p, SingI s) => Bool -> Contract p s -> Text
- Michelson.Printer: printUntypedContract :: RenderDoc op => Contract' op -> Text
+ Michelson.Printer: printUntypedContract :: RenderDoc op => Bool -> Contract' op -> Text
- Michelson.Printer: renderDoc :: RenderDoc a => a -> Doc
+ Michelson.Printer: renderDoc :: RenderDoc a => RenderContext -> a -> Doc
- Michelson.Printer.Util: printDoc :: Doc -> Text
+ Michelson.Printer.Util: printDoc :: Bool -> Doc -> Text
- Michelson.Printer.Util: renderDoc :: RenderDoc a => a -> Doc
+ Michelson.Printer.Util: renderDoc :: RenderDoc a => RenderContext -> a -> Doc
- Michelson.Printer.Util: wrapInParens :: NonEmpty Doc -> Doc
+ Michelson.Printer.Util: wrapInParens :: RenderContext -> NonEmpty Doc -> Doc
- Michelson.Runtime: ContractState :: !Mutez -> !Value -> !Contract -> ContractState
+ Michelson.Runtime: ContractState :: !Mutez -> !Value -> !Contract -> !Maybe SomeContract -> !Maybe SomeValue -> ContractState
- Michelson.Runtime: IEInterpreterFailed :: !a -> !InterpretUntypedError -> InterpreterError' a
+ Michelson.Runtime: IEInterpreterFailed :: !a -> !InterpretError -> InterpreterError' a
- Michelson.Runtime: InterpreterRes :: !GState -> [InterpreterOp] -> ![GStateUpdate] -> [(Address, InterpretUntypedResult)] -> !Maybe Address -> !RemainingSteps -> InterpreterRes
+ Michelson.Runtime: InterpreterRes :: !GState -> [InterpreterOp] -> ![GStateUpdate] -> [(Address, InterpretResult)] -> !Maybe Address -> !RemainingSteps -> InterpreterRes
- Michelson.Runtime: [_irInterpretResults] :: InterpreterRes -> [(Address, InterpretUntypedResult)]
+ Michelson.Runtime: [_irInterpretResults] :: InterpreterRes -> [(Address, InterpretResult)]
- Michelson.Runtime: irInterpretResults :: Lens' InterpreterRes [(Address, InterpretUntypedResult)]
+ Michelson.Runtime: irInterpretResults :: Lens' InterpreterRes [(Address, InterpretResult)]
- Michelson.Runtime.GState: ContractState :: !Mutez -> !Value -> !Contract -> ContractState
+ Michelson.Runtime.GState: ContractState :: !Mutez -> !Value -> !Contract -> !Maybe SomeContract -> !Maybe SomeValue -> ContractState
- Michelson.Runtime.GState: GSSetStorageValue :: !Address -> !Value -> GStateUpdate
+ Michelson.Runtime.GState: GSSetStorageValue :: !Address -> !Value -> !SomeValue -> GStateUpdate
- Michelson.Runtime.GState: GState :: Map Address AddressState -> GState
+ Michelson.Runtime.GState: GState :: ChainId -> Map Address AddressState -> GState
- Michelson.Test: integrationalTestExpectation :: IntegrationalScenario -> Expectation
+ Michelson.Test: integrationalTestExpectation :: HasCallStack => IntegrationalScenario -> Expectation
- Michelson.Test: type IntegrationalScenarioM = StateT InternalState (Except ValidationError)
+ Michelson.Test: type IntegrationalScenarioM = StateT InternalState (Except ScenarioError)
- Michelson.Test: type SuccessValidator = (InternalState -> GState -> [GStateUpdate] -> Either ValidationError ())
+ Michelson.Test: type SuccessValidator = InternalState -> GState -> [GStateUpdate] -> Either ValidationError ()
- Michelson.Test.Integrational: integrationalTestExpectation :: IntegrationalScenario -> Expectation
+ Michelson.Test.Integrational: integrationalTestExpectation :: HasCallStack => IntegrationalScenario -> Expectation
- Michelson.Test.Integrational: type IntegrationalScenarioM = StateT InternalState (Except ValidationError)
+ Michelson.Test.Integrational: type IntegrationalScenarioM = StateT InternalState (Except ScenarioError)
- Michelson.Test.Integrational: type SuccessValidator = (InternalState -> GState -> [GStateUpdate] -> Either ValidationError ())
+ Michelson.Test.Integrational: type SuccessValidator = InternalState -> GState -> [GStateUpdate] -> Either ValidationError ()
- Michelson.TypeCheck: typeCheckValue :: Value -> (Sing t, Notes t) -> TypeCheckInstr SomeValue
+ Michelson.TypeCheck: typeCheckValue :: Value -> (Sing t, Notes t) -> TypeCheckInstr SomeNotedValue
- Michelson.TypeCheck.Helpers: compareImpl :: forall a b inp rs m. (Typeable rs, Each [Typeable, SingI] [a, b], inp ~ ( 'Tc a : ( 'Tc b : rs)), MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> Sing b -> HST inp -> VarAnn -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: compareImpl :: forall a inp rs m. (Typeable rs, With [Typeable, SingI] a, inp ~ ( 'Tc a : ( 'Tc a : rs)), MonadReader InstrCallStack m) => Sing a -> HST inp -> VarAnn -> m (SomeInstr inp)
- Michelson.TypeCheck.Helpers: updImpl :: forall c updKey updParams rs inp m. (UpdOp c, Typeable (UpdOpKey c), SingI (UpdOpKey c), Typeable (UpdOpParams c), SingI (UpdOpParams c), inp ~ (updKey : (updParams : (c : rs))), MonadReader InstrCallStack m, MonadError TCError m) => ExpandedInstr -> HST (updKey : (updParams : (c : rs))) -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: updImpl :: forall c updKey updParams rs inp m. (UpdOp c, Typeable (UpdOpKey c), SingI (UpdOpKey c), Typeable (UpdOpParams c), SingI (UpdOpParams c), inp ~ (updKey : (updParams : (c : rs))), MonadReader InstrCallStack m, MonadError TCError m) => ExpandedInstr -> HST (updKey : (updParams : (c : rs))) -> VarAnn -> m (SomeInstr inp)
- Michelson.TypeCheck.Instr: typeCheckValue :: Value -> (Sing t, Notes t) -> TypeCheckInstr SomeValue
+ Michelson.TypeCheck.Instr: typeCheckValue :: Value -> (Sing t, Notes t) -> TypeCheckInstr SomeNotedValue
- Michelson.TypeCheck.TypeCheck: type TcOriginatedContracts = Map Address Type
+ Michelson.TypeCheck.TypeCheck: type TcOriginatedContracts = Map ContractHash Type
- Michelson.TypeCheck.Types: [::::] :: (SingI t, Typeable t) => Value t -> (Sing t, Notes t) -> SomeValue
+ Michelson.TypeCheck.Types: [::::] :: (SingI t, Typeable t) => Value t -> (Sing t, Notes t) -> SomeNotedValue
- Michelson.TypeCheck.Types: [SomeContract] :: (Each [Typeable, SingI, HasNoOp] [st, cp], HasNoBigMap cp, BigMapConstraint st) => Contract cp st -> HST (ContractInp cp st) -> HST (ContractOut st) -> SomeContract
+ Michelson.TypeCheck.Types: [SomeContract] :: FullContract cp st -> SomeContract
- Michelson.TypeCheck.Value: typeCheckValImpl :: TcInstrHandler -> Value -> (Sing t, Notes t) -> TypeCheckInstr SomeValue
+ Michelson.TypeCheck.Value: typeCheckValImpl :: TcInstrHandler -> Value -> (Sing t, Notes t) -> TypeCheckInstr SomeNotedValue
- Michelson.Typed.Annotation: [NTBigMap] :: TypeAnn -> TypeAnn -> Notes v -> Notes' ( 'TBigMap k v)
+ Michelson.Typed.Annotation: [NTBigMap] :: TypeAnn -> TypeAnn -> Notes v -> Notes ( 'TBigMap k v)
- Michelson.Typed.Annotation: [NTContract] :: TypeAnn -> Notes t -> Notes' ( 'TContract t)
+ Michelson.Typed.Annotation: [NTContract] :: TypeAnn -> Notes t -> Notes ( 'TContract t)
- Michelson.Typed.Annotation: [NTKey] :: TypeAnn -> Notes' 'TKey
+ Michelson.Typed.Annotation: [NTKey] :: TypeAnn -> Notes 'TKey
- Michelson.Typed.Annotation: [NTLambda] :: TypeAnn -> Notes p -> Notes q -> Notes' ( 'TLambda p q)
+ Michelson.Typed.Annotation: [NTLambda] :: TypeAnn -> Notes p -> Notes q -> Notes ( 'TLambda p q)
- Michelson.Typed.Annotation: [NTList] :: TypeAnn -> Notes t -> Notes' ( 'TList t)
+ Michelson.Typed.Annotation: [NTList] :: TypeAnn -> Notes t -> Notes ( 'TList t)
- Michelson.Typed.Annotation: [NTMap] :: TypeAnn -> TypeAnn -> Notes v -> Notes' ( 'TMap k v)
+ Michelson.Typed.Annotation: [NTMap] :: TypeAnn -> TypeAnn -> Notes v -> Notes ( 'TMap k v)
- Michelson.Typed.Annotation: [NTOperation] :: TypeAnn -> Notes' 'TOperation
+ Michelson.Typed.Annotation: [NTOperation] :: TypeAnn -> Notes 'TOperation
- Michelson.Typed.Annotation: [NTOption] :: TypeAnn -> FieldAnn -> Notes t -> Notes' ( 'TOption t)
+ Michelson.Typed.Annotation: [NTOption] :: TypeAnn -> Notes t -> Notes ( 'TOption t)
- Michelson.Typed.Annotation: [NTOr] :: TypeAnn -> FieldAnn -> FieldAnn -> Notes p -> Notes q -> Notes' ( 'TOr p q)
+ Michelson.Typed.Annotation: [NTOr] :: TypeAnn -> FieldAnn -> FieldAnn -> Notes p -> Notes q -> Notes ( 'TOr p q)
- Michelson.Typed.Annotation: [NTPair] :: TypeAnn -> FieldAnn -> FieldAnn -> Notes p -> Notes q -> Notes' ( 'TPair p q)
+ Michelson.Typed.Annotation: [NTPair] :: TypeAnn -> FieldAnn -> FieldAnn -> Notes p -> Notes q -> Notes ( 'TPair p q)
- Michelson.Typed.Annotation: [NTSet] :: TypeAnn -> TypeAnn -> Notes' ( 'TSet ct)
+ Michelson.Typed.Annotation: [NTSet] :: TypeAnn -> TypeAnn -> Notes ( 'TSet ct)
- Michelson.Typed.Annotation: [NTSignature] :: TypeAnn -> Notes' 'TSignature
+ Michelson.Typed.Annotation: [NTSignature] :: TypeAnn -> Notes 'TSignature
- Michelson.Typed.Annotation: [NTUnit] :: TypeAnn -> Notes' 'TUnit
+ Michelson.Typed.Annotation: [NTUnit] :: TypeAnn -> Notes 'TUnit
- Michelson.Typed.Annotation: [NTc] :: TypeAnn -> Notes' ( 'Tc ct)
+ Michelson.Typed.Annotation: [NTc] :: TypeAnn -> Notes ( 'Tc ct)
- Michelson.Typed.Annotation: isStar :: Notes t -> Bool
+ Michelson.Typed.Annotation: isStar :: SingI t => Notes t -> Bool
- Michelson.Typed.CValue: [CvAddress] :: Address -> CValue 'CAddress
+ Michelson.Typed.CValue: [CvAddress] :: EpAddress -> CValue 'CAddress
- Michelson.Typed.Convert: instrToOps :: Instr inp out -> [ExpandedOp]
+ Michelson.Typed.Convert: instrToOps :: HasCallStack => Instr inp out -> [ExpandedOp]
- Michelson.Typed.Extract: fromUType :: HasCallStack => Type -> T
+ Michelson.Typed.Extract: fromUType :: Type -> T
- Michelson.Typed.Haskell: (//->) :: Label ("c" `AppendSymbol` ctor) -> Instr (AppendCtorField x inp) out -> CaseClause inp out ( 'CaseClauseParam ctor x)
+ Michelson.Typed.Haskell: (//->) :: Label ("c" `AppendSymbol` ctor) -> RemFail Instr (AppendCtorField x inp) out -> CaseClause inp out ( 'CaseClauseParam ctor x)
- Michelson.Typed.Haskell: [CaseClause] :: Instr (AppendCtorField x inp) out -> CaseClause inp out ( 'CaseClauseParam ctor x)
+ Michelson.Typed.Haskell: [CaseClause] :: RemFail Instr (AppendCtorField x inp) out -> CaseClause inp out ( 'CaseClauseParam ctor x)
- Michelson.Typed.Haskell: instrCase :: forall dt out inp. InstrCaseC dt inp out => Rec (CaseClause inp out) (CaseClauses dt) -> Instr (ToT dt : inp) out
+ Michelson.Typed.Haskell: instrCase :: forall dt out inp. InstrCaseC dt inp out => Rec (CaseClause inp out) (CaseClauses dt) -> RemFail Instr (ToT dt : inp) out
- Michelson.Typed.Haskell.Instr.Sum: (//->) :: Label ("c" `AppendSymbol` ctor) -> Instr (AppendCtorField x inp) out -> CaseClause inp out ( 'CaseClauseParam ctor x)
+ Michelson.Typed.Haskell.Instr.Sum: (//->) :: Label ("c" `AppendSymbol` ctor) -> RemFail Instr (AppendCtorField x inp) out -> CaseClause inp out ( 'CaseClauseParam ctor x)
- Michelson.Typed.Haskell.Instr.Sum: [CaseClause] :: Instr (AppendCtorField x inp) out -> CaseClause inp out ( 'CaseClauseParam ctor x)
+ Michelson.Typed.Haskell.Instr.Sum: [CaseClause] :: RemFail Instr (AppendCtorField x inp) out -> CaseClause inp out ( 'CaseClauseParam ctor x)
- Michelson.Typed.Haskell.Instr.Sum: instrCase :: forall dt out inp. InstrCaseC dt inp out => Rec (CaseClause inp out) (CaseClauses dt) -> Instr (ToT dt : inp) out
+ Michelson.Typed.Haskell.Instr.Sum: instrCase :: forall dt out inp. InstrCaseC dt inp out => Rec (CaseClause inp out) (CaseClauses dt) -> RemFail Instr (ToT dt : inp) out
- Michelson.Typed.Haskell.Instr.Sum: type family AppendCtorField (cf :: CtorField) (l :: [k]) :: [k]
+ Michelson.Typed.Haskell.Instr.Sum: type family IsPrimitiveValue (x :: Type) :: Bool
- Michelson.Typed.Instr: [COMPARE] :: (ArithOp Compare n m, Typeable n, Typeable m) => Instr ( 'Tc n : ( 'Tc m : s)) ( 'Tc (ArithRes Compare n m) : s)
+ Michelson.Typed.Instr: [COMPARE] :: (ArithOp Compare n n, Typeable n) => Instr ( 'Tc n : ( 'Tc n : s)) ( 'Tc (ArithRes Compare n n) : s)
- Michelson.Typed.Instr: [CONTRACT] :: (SingI p, Typeable p) => Notes p -> Instr ( 'Tc 'CAddress : s) ( 'TOption ( 'TContract p) : s)
+ Michelson.Typed.Instr: [CONTRACT] :: ParameterScope p => Notes p -> EpName -> Instr ( 'Tc 'CAddress : s) ( 'TOption ( 'TContract p) : s)
- Michelson.Typed.Instr: [CREATE_CONTRACT] :: (Each [Typeable, SingI, HasNoOp] [p, g], HasNoBigMap p, BigMapConstraint g) => Instr '[ 'TPair p g] '[ 'TPair ( 'TList 'TOperation) g] -> Instr ( 'Tc 'CKeyHash : ( 'TOption ( 'Tc 'CKeyHash) : ( 'Tc 'CBool : ( 'Tc 'CBool : ( 'Tc 'CMutez : (g : s)))))) ( 'TOperation : ( 'Tc 'CAddress : s))
+ Michelson.Typed.Instr: [CREATE_CONTRACT] :: (ParameterScope p, StorageScope g) => FullContract p g -> Instr ( 'TOption ( 'Tc 'CKeyHash) : ( 'Tc 'CMutez : (g : s))) ( 'TOperation : ( 'Tc 'CAddress : s))
- Michelson.Typed.Instr: [PACK] :: (SingI a, HasNoOp a, HasNoBigMap a) => Instr (a : s) ( 'Tc 'CBytes : s)
+ Michelson.Typed.Instr: [PACK] :: PackedValScope a => Instr (a : s) ( 'Tc 'CBytes : s)
- Michelson.Typed.Instr: [PUSH] :: forall t s. (SingI t, HasNoOp t, HasNoBigMap t) => Value' Instr t -> Instr s (t : s)
+ Michelson.Typed.Instr: [PUSH] :: forall t s. ConstantScope t => Value' Instr t -> Instr s (t : s)
- Michelson.Typed.Instr: [SELF] :: forall (cp :: T) s. Instr s ( 'TContract cp : s)
+ Michelson.Typed.Instr: [SELF] :: forall (p :: T) s. ParameterScope p => Instr s ( 'TContract p : s)
- Michelson.Typed.Instr: [StackRef] :: (KnownPeano idx, LongerThan st idx) => Sing (idx :: Peano) -> StackRef st
+ Michelson.Typed.Instr: [StackRef] :: (KnownPeano idx, SingI idx, RequireLongerThan st idx) => Sing (idx :: Peano) -> StackRef st
- Michelson.Typed.Instr: [TRANSFER_TOKENS] :: (Typeable p, SingI p, HasNoOp p, HasNoBigMap p) => Instr (p : ( 'Tc 'CMutez : ( 'TContract p : s))) ( 'TOperation : s)
+ Michelson.Typed.Instr: [TRANSFER_TOKENS] :: ParameterScope p => Instr (p : ( 'Tc 'CMutez : ( 'TContract p : s))) ( 'TOperation : s)
- Michelson.Typed.Instr: [UNPACK] :: (SingI a, HasNoOp a, HasNoBigMap a) => Instr ( 'Tc 'CBytes : s) ( 'TOption a : s)
+ Michelson.Typed.Instr: [UNPACK] :: UnpackedValScope a => Instr ( 'Tc 'CBytes : s) ( 'TOption a : s)
- Michelson.Typed.Value: CreateContract :: !KeyHash -> !Maybe KeyHash -> !Bool -> !Bool -> !Mutez -> !Value' instr st -> !instr (ContractInp cp st) (ContractOut st) -> CreateContract instr cp st
+ Michelson.Typed.Value: CreateContract :: !Address -> !Maybe KeyHash -> !Mutez -> !Value' instr st -> !instr (ContractInp cp st) (ContractOut st) -> CreateContract instr cp st
- Michelson.Typed.Value: [CvAddress] :: Address -> CValue 'CAddress
+ Michelson.Typed.Value: [CvAddress] :: EpAddress -> CValue 'CAddress
- Michelson.Typed.Value: [OpCreateContract] :: (Show (instr (ContractInp cp st) (ContractOut st)), SingI cp, SingI st, Typeable instr, Typeable cp, Typeable st, HasNoOp cp, HasNoOp st) => CreateContract instr cp st -> Operation' instr
+ Michelson.Typed.Value: [OpCreateContract] :: (Show (instr (ContractInp cp st) (ContractOut st)), Typeable instr, ParameterScope cp, StorageScope st) => CreateContract instr cp st -> Operation' instr
- Michelson.Typed.Value: [OpTransferTokens] :: (Typeable p, SingI p, HasNoOp p) => TransferTokens instr p -> Operation' instr
+ Michelson.Typed.Value: [OpTransferTokens] :: ParameterScope p => TransferTokens instr p -> Operation' instr
- Michelson.Typed.Value: [VContract] :: forall p instr. Address -> Value' instr ( 'TContract p)
+ Michelson.Typed.Value: [VContract] :: forall arg instr. Address -> SomeEntryPointCallT arg -> Value' instr ( 'TContract arg)
- Michelson.Typed.Value: [VLam] :: forall inp out instr. (Show (instr '[inp] '[out]), Eq (instr '[inp] '[out])) => instr (inp : '[]) (out : '[]) -> Value' instr ( 'TLambda inp out)
+ Michelson.Typed.Value: [VLam] :: forall inp out instr. forall i o. (Show (instr i o), Eq (instr i o)) => RemFail instr (inp : '[]) (out : '[]) -> Value' instr ( 'TLambda inp out)
- Michelson.Untyped.Annotation: renderAnn :: RenderAnn t => t -> Doc
+ Michelson.Untyped.Annotation: renderAnn :: forall tag. KnownAnnTag tag => Annotation tag -> Doc
- Michelson.Untyped.Instr: CONTRACT :: VarAnn -> Type -> InstrAbstract op
+ Michelson.Untyped.Instr: CONTRACT :: VarAnn -> FieldAnn -> Type -> InstrAbstract op
- Michelson.Untyped.Instr: NEG :: InstrAbstract op
+ Michelson.Untyped.Instr: NEG :: VarAnn -> InstrAbstract op
- Michelson.Untyped.Instr: NONE :: TypeAnn -> VarAnn -> FieldAnn -> Type -> InstrAbstract op
+ Michelson.Untyped.Instr: NONE :: TypeAnn -> VarAnn -> Type -> InstrAbstract op
- Michelson.Untyped.Instr: OriginationOperation :: !KeyHash -> !Maybe KeyHash -> !Bool -> !Bool -> !Mutez -> !Value' ExpandedOp -> !Contract' ExpandedOp -> OriginationOperation
+ Michelson.Untyped.Instr: OriginationOperation :: !Address -> !Maybe KeyHash -> !Mutez -> !Value' ExpandedOp -> !Contract' ExpandedOp -> OriginationOperation
- Michelson.Untyped.Instr: SOME :: TypeAnn -> VarAnn -> FieldAnn -> InstrAbstract op
+ Michelson.Untyped.Instr: SOME :: TypeAnn -> VarAnn -> InstrAbstract op
- Michelson.Untyped.Instr: UPDATE :: InstrAbstract op
+ Michelson.Untyped.Instr: UPDATE :: VarAnn -> InstrAbstract op
- Michelson.Untyped.Type: TOption :: FieldAnn -> Type -> T
+ Michelson.Untyped.Type: TOption :: Type -> T
- Tezos.Address: ContractAddress :: !ByteString -> Address
+ Tezos.Address: ContractAddress :: !ContractHash -> Address
- Tezos.Core: timestampFromSeconds :: Integral a => a -> Timestamp
+ Tezos.Core: timestampFromSeconds :: Integer -> Timestamp
- Tezos.Crypto: CryptoParseCryptoError :: CryptoError -> CryptoParseError
+ Tezos.Crypto: CryptoParseCryptoError :: !CryptoError -> CryptoParseError
- Tezos.Crypto: KeyHash :: ByteString -> KeyHash
+ Tezos.Crypto: KeyHash :: KeyHashTag -> ByteString -> KeyHash
- Tezos.Crypto: detSecretKey :: ByteString -> SecretKey
+ Tezos.Crypto: detSecretKey :: HasCallStack => ByteString -> SecretKey
- Tezos.Crypto: mkSignature :: ByteArrayAccess ba => ba -> Either Text Signature
+ Tezos.Crypto: mkSignature :: ByteArray ba => ba -> Maybe Signature
- Util.Generic: mkGenericTree :: (Int -> a -> a -> a) -> NonEmpty a -> a
+ Util.Generic: mkGenericTree :: (Natural -> a -> a -> a) -> NonEmpty a -> a
- Util.Generic: mkGenericTreeVec :: HasCallStack => (a -> b) -> (Int -> b -> b -> b) -> Vector a -> b
+ Util.Generic: mkGenericTreeVec :: HasCallStack => (a -> b) -> (Natural -> b -> b -> b) -> Vector a -> b
- Util.Named: type family NamedInner n
+ Util.Named: type family NamedInner (n :: Type)
- Util.Peano: class KnownPeano (n :: Nat)
+ Util.Peano: class KnownPeano (n :: Peano)
- Util.Peano: type family RequireLongerThan (l :: [k]) (a :: Nat) :: Constraint
+ Util.Peano: type family IsLongerOrSameLength (l :: [k]) (a :: Peano) :: Bool
- Util.Type: type family IsElem (a :: k) (l :: [k]) :: Bool
+ Util.Type: type family PatternMatchL (l :: [k]) :: Constraint

Files

CHANGES.md view
@@ -1,3 +1,20 @@+0.4.0+=====++* Implemented most of Babylon changes: new instructions, elimination of `big_map` restructions, new restrictions for the `contract` type, partial support for entrypoints. Some instructions have been removed/deprecated.+* Many updates of helper data types for upgradeable contracts: `UParam` and `UStore`.+* Michelson printer can produce pretty output, not just one line.+* Added utilities for contract processing and analysis: optimizer, string transformer, errors transformer, analyzer.+* Added `tasty` helpers to the testing engine.+* Added annotations to typed representation and Lorentz.+* Added automatic documentation generator.+* Modified standard errors in Lorentz: now they are based on `CustomError`.+* Added unpacking from readable representation.+* Removed `parameter` and `storage` aliases, they were not very useful and complicated the code.+* Extended cryptographic types and `Address` to work with other curves (tz2 and tz3 addresses).+* Made it nearly impossible to generate dead code (which is illegal in Michelson) using Lorentz.+* Various bug fixes.+ 0.3.0.1 ======= 
CONTRIBUTING.md view
@@ -2,13 +2,12 @@  ## Reporting Issues -Please [open an issue](https://issues.serokell.io/newIssue?project=TM)+Please [open an issue](https://gitlab.com/morley-framework/morley/issues/new) if you find a bug or have a feature request.-Note: you need to login (e. g. using your GitHub account) first. Before submitting a bug report or feature request, check to make sure it hasn't already been submitted.  The more detailed your report is, the faster it can be resolved.-If you report a bug, please provide steps to reproduce this bug and revision of code in which this bug reproduces.+Please use issue templates to create an issue.  ## Code @@ -46,7 +45,7 @@ common developers' activities, like building with flags suitable for development, testing, applying `stylish-haskell` and `hlint`, building Haddock documentation. Mentioned `Makefile` builds morley itself,-each extra package, like [`lorentz-contracts`](/lorentz-contracts/Makefile),+each extra package, like [`morley-ledgers`](/morley-ledgers/Makefile), has its own `Makefile`.  If you want to run test suite with additional options, set `TEST_ARGUMENTS` variable.@@ -64,11 +63,11 @@  As soon as this repository uses different default extensions in different packages, Intero may report non-existing errors.-This issue [is known](https://github.com/chrisdone/intero/issues/554) and probably-won't be resolved soon.+This issue is known (once located under https://github.com/chrisdone/intero/issues/554)+and will never be resolved unless `intero` project is resurrected.  However, with proper care, this problem can be avoided. Just follow the rules: * When working with `morley` package, select only `morley:*` packages in `intero-targets`.-* When developing on Lorentz within `lorentz-contracts` package, make sure that+* When developing on Lorentz within e. g. `morley-ledgers` package, make sure that you first built morley core with `make morley`, only after that open the Lorentz modules.-Then set `lorentz-contracts:*` packages as intero targets.+Then set `morley-ledgers:*` packages as intero targets.
README.md view
@@ -5,11 +5,6 @@ Morley is a library to make writing smart contracts in Michelson pleasant and effective. -## ZuriHac notice--Morley is one of the projects at [ZuriHac 2019](https://zfoh.ch/zurihac2019/).-If you want to participate, please go to https://morley-zurihac.serokell.io/ to get more information.- ## I: A reimplementation of the Michelson Language in Haskell  It consists of the following parts:@@ -50,9 +45,10 @@ Later Lorentz contract can be dumped as a plain textual Michelson contract using functions from [`Michelson.Printer`](/src/Michelson/Printer.hs).  You can find Lorentz instructions in [`Lorentz`](/src/Lorentz.hs) modules.-Examples reside in [`Lorentz.Contracts.*`](/lorentz-contracts/src/Lorentz/Contracts/) modules.-For more information, refer this package [README](/lorentz-contracts/README.md). +Examples of using Lorentz eDSL reside in the [`morley-ledgers`](/morley-ledgers) package.+For more information, refer to this package [README](/morley-ledgers/README.md).+ ## V: Testing EDSL  Another way to test Michelson contracts is to write tests in Haskell using the testing EDSL provided by Morley.@@ -85,17 +81,32 @@     after that you can do `stack exec -- morley <args>` to run morley executable built from the source code.   * Usage example:     + `stack exec -- morley --help` to see help message-    + `stack exec -- morley originate --contract contracts/add1.tz --storage 1 --verbose`+    + `stack exec -- morley originate --contract contracts/tezos_examples/attic/add1.tz --storage 1 --verbose`+- [Cabal](https://www.haskell.org/cabal/) based.+  * Clone this git repository and run `cabal new-update && cabal new-build` command,+    after that you can do `cabal run -- morley <args>` to run morley executable built from the source code.+  * Usage example:+    + `cabal run -- morley --help` to see help message+    + `cabal run -- morley originate --contract contracts/tezos_examples/attic/add1.tz --storage 1 --verbose`  For more information about Morley commands, check out the following docs: - [Interpreter doc](/docs/morleyInterpreter.md) - [Typechecker doc](/docs/morleyTypechecker.md) +## Michelson version++`master` and `production` branches are maintained to be compatible with version of Michelson running on mainnet.+We use separate branches to support other versions.+More information about our branching strategy can be found [here](/docs/branching.md).+ ## Issue Tracker -We use [YouTrack](https://issues.serokell.io/issues/TM) as our issue-tracker. You can login using your GitHub account to leave a comment or-create a new issue.+We used to use [YouTrack](https://issues.serokell.io/issues/TM) as our primary issue tracker.+You may see that commit messages up to some date are prefixed with `[TM-X]`.+This prefix refers to an issue in our YouTrack.+YouTrack issues are public, so you can open any of them.++Nowadays we are using built-in issue tracker on GitLab.  ## For Contributors 
app/Main.hs view
@@ -5,7 +5,7 @@ import qualified Control.Exception as E import Data.Version (showVersion) import Fmt (pretty)-import Named ((:?), argF, (!))+import Named ((:!), (:?), arg, argF, (!)) import Options.Applicative   (auto, command, eitherReader, execParser, footerDoc, fullDesc, header, help, helper, info,   infoOption, long, maybeReader, metavar, option, progDesc, readerError, short, showDefault,@@ -18,13 +18,17 @@ import Text.Pretty.Simple (pPrint) import qualified Text.Show -import Michelson.Macro (expandContract, expandValue)+import Michelson.Analyzer (analyze)+import Michelson.Macro (expandContract)+import Michelson.Optimizer (optimize) import qualified Michelson.Parser as P-import Michelson.Printer (printUntypedContract)+import Michelson.Printer (printSomeContract, printUntypedContract) import Michelson.Runtime   (TxData(..), originateContract, prepareContract, readAndParseContract, runContract, transfer,   typeCheckWithDb)-import Michelson.Runtime.GState (genesisAddress, genesisKeyHash)+import Michelson.Runtime.GState (genesisAddress)+import Michelson.TypeCheck.Types (SomeContract(..), mapSomeContract)+import Michelson.Typed (FullContract(..)) import Michelson.Untyped hiding (OriginationOperation(..)) import qualified Michelson.Untyped as U import Tezos.Address (Address, parseAddress)@@ -40,12 +44,26 @@  data CmdLnArgs   = Parse (Maybe FilePath) Bool-  | Print ("input" :? FilePath) ("output" :? FilePath)+  | Print ("input" :? FilePath) ("output" :? FilePath) ("singleLine" :! Bool)+  | Optimize !OptimizeOptions+  | Analyze !AnalyzeOptions   | TypeCheck !TypeCheckOptions   | Run !RunOptions   | Originate !OriginateOptions   | Transfer !TransferOptions +data OptimizeOptions = OptimizeOptions+  { optoContractFile :: !(Maybe FilePath)+  , optoDBPath :: !FilePath+  , optoOutput :: !(Maybe FilePath)+  , optoSingleLine :: !Bool+  }++data AnalyzeOptions = AnalyzeOptions+  { aoContractFile :: !(Maybe FilePath)+  , aoDBPath :: !FilePath+  }+ data TypeCheckOptions = TypeCheckOptions   { tcoContractFile :: !(Maybe FilePath)   , tcoDBPath       :: !FilePath@@ -62,15 +80,14 @@   , roMaxSteps :: !Word64   , roInitBalance :: !Mutez   , roWrite :: !Bool+    -- TODO [TM-280]: add `--entrypoint` option   }  data OriginateOptions = OriginateOptions   { ooContractFile :: !(Maybe FilePath)   , ooDBPath :: !FilePath-  , ooManager :: !KeyHash+  , ooOriginator :: !Address   , ooDelegate :: !(Maybe KeyHash)-  , ooSpendable :: !Bool-  , ooDelegatable :: !Bool   , ooStorageValue :: !U.Value   , ooBalance :: !Mutez   , ooVerbose :: !Bool@@ -93,7 +110,9 @@   typecheckSubCmd <>   runSubCmd <>   originateSubCmd <>-  transferSubCmd+  transferSubCmd <>+  optimizeSubCmd <>+  analyzeSubCmd   where     mkCommandParser commandName parser desc =       command commandName $@@ -112,7 +131,9 @@      printSubCmd =       mkCommandParser "print"-      (Print <$> (#input <.?> contractFileOption) <*> (#output <.?> outputOption))+      (Print <$> (#input <.?> contractFileOption)+             <*> (#output <.?> outputOption)+             <*> (#singleLine <.!> onelineOption))       ("Parse a Morley contract and print corresponding Michelson " <>        "contract that can be parsed by the OCaml reference client") @@ -132,6 +153,16 @@       (Transfer <$> transferOptions)       "Transfer tokens to given address" +    optimizeSubCmd =+      mkCommandParser "optimize"+      (Optimize <$> optimizeOptions)+      "Optimize the contract."++    analyzeSubCmd =+      mkCommandParser "analyze"+      (Analyze <$> analyzeOptions)+      "Analyze the contract."+     verboseFlag :: Opt.Parser Bool     verboseFlag = switch $       short 'v' <>@@ -164,6 +195,18 @@     defaultBalance :: Mutez     defaultBalance = unsafeMkMutez 4000000 +    optimizeOptions :: Opt.Parser OptimizeOptions+    optimizeOptions = OptimizeOptions+      <$> contractFileOption+      <*> dbPathOption+      <*> outputOption+      <*> onelineOption++    analyzeOptions :: Opt.Parser AnalyzeOptions+    analyzeOptions = AnalyzeOptions+      <$> contractFileOption+      <*> dbPathOption+     runOptions :: Opt.Parser RunOptions     runOptions =       RunOptions@@ -183,13 +226,9 @@       OriginateOptions         <$> contractFileOption         <*> dbPathOption-        <*> keyHashOption (Just genesisKeyHash) "manager" "Contract's manager"+        <*> addressOption (Just genesisAddress) "originator" "Contract's originator"         <*> optional             (keyHashOption Nothing "delegate" "Contract's optional delegate")-        <*> switch (long "spendable" <>-                    help "Whether the contract is spendable")-        <*> switch (long "delegatable" <>-                    help "Whether the contract is delegatable")         <*> valueOption "storage" "Initial storage of an originating contract"         <*> mutezOption (Just defaultBalance)             "balance" "Initial balance of an originating contract"@@ -206,6 +245,7 @@       toDryRun <- dryRunFlag       pure TransferOptions {..} + contractFileOption :: Opt.Parser (Maybe FilePath) contractFileOption = optional $ strOption $   long "contract" <>@@ -219,7 +259,7 @@   help "Timestamp that you want the runtime interpreter to use (default is now)"   where     parser =-      (timestampFromSeconds @Integer <$> auto) <|>+      (timestampFromSeconds <$> auto) <|>       maybeReader (parseTimestamp . toText)  maxStepsOption :: Opt.Parser Word64@@ -251,10 +291,10 @@   help hInfo   where     parseValue :: String -> Either String U.Value-    parseValue s =-      either (Left . mappend "Failed to parse value: " . show)-             (Right . expandValue)-      $ P.parseNoEnv P.value "" (toText s)+    parseValue =+      first (mappend "Failed to parse value: " . displayException) .+      P.parseExpandValue .+      toText  mutezOption :: Maybe Mutez -> String -> String -> Opt.Parser Mutez mutezOption defaultValue name hInfo =@@ -277,6 +317,11 @@       either (Left . mappend "Failed to parse address: " . pretty) Right $       parseAddress $ toText addr +onelineOption :: Opt.Parser Bool+onelineOption = switch (+  long "oneline" <>+  help "Force single line output")+ outputOption :: Opt.Parser (Maybe FilePath) outputOption = optional . strOption $   short 'o' <>@@ -372,10 +417,24 @@         if hasExpandMacros           then pPrint $ expandContract contract           else pPrint contract-      Print (argF #input -> mInputFile) (argF #output -> mOutputFile) -> do+      Print (argF #input -> mInputFile)+            (argF #output -> mOutputFile)+            (arg #singleLine -> forceSingleLine) -> do         contract <- prepareContract mInputFile         let write = maybe putStrLn writeFileUtf8 mOutputFile-        write $ printUntypedContract contract+        write $ printUntypedContract forceSingleLine contract+      Optimize OptimizeOptions{..} -> do+        untypedContract <- prepareContract optoContractFile+        checkedContract <- either throwM pure =<<+          typeCheckWithDb optoDBPath untypedContract+        let optimizedContract = mapSomeContract optimize checkedContract+        let write = maybe putStrLn writeFileUtf8 optoOutput+        write $ printSomeContract optoSingleLine optimizedContract+      Analyze AnalyzeOptions{..} -> do+        untypedContract <- prepareContract aoContractFile+        SomeContract contract <- either throwM pure =<<+          typeCheckWithDb aoDBPath untypedContract+        putTextLn $ pretty $ analyze (fcCode contract)       TypeCheck TypeCheckOptions{..} -> do         morleyContract <- prepareContract tcoContractFile         either throwM (const pass) =<< typeCheckWithDb tcoDBPath morleyContract@@ -388,10 +447,8 @@       Originate OriginateOptions {..} -> do         michelsonContract <- prepareContract ooContractFile         let origination = U.OriginationOperation-              { U.ooManager = ooManager+              { U.ooOriginator = ooOriginator               , U.ooDelegate = ooDelegate-              , U.ooSpendable = ooSpendable-              , U.ooDelegatable = ooDelegatable               , U.ooStorage = ooStorageValue               , U.ooBalance = ooBalance               , U.ooContract = michelsonContract@@ -402,6 +459,7 @@         transfer toNow toMaxSteps toDBPath toDestination toTxData           ! #verbose toVerbose           ! #dryRun toDryRun+  usageDoc :: Maybe Doc usageDoc = Just $ mconcat
− contract-discover/Main.hs
@@ -1,155 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}---- | An executable for haskell preprocessor which finds--- all contract declarations in Haskell modules within the directory where--- preprocessor is called and exports found contracts in a map.-module Main-  ( main-  ) where--import qualified Unsafe--import Data.Default (Default(..))-import Fmt (Builder, build, fmt, indentF, listF', unlinesF, (+|), (+||), (|+), (||+))-import qualified System.Directory as Dir-import System.Environment (getArgs)-import System.FilePath.Posix (isAbsolute, takeDirectory, (</>))-import Text.Megaparsec (errorBundlePretty, runParser)--import Lorentz.Discover-import Util.IO (hSetTranslit, readFileUtf8, writeFileUtf8)--main :: IO ()-main = do-  hSetTranslit stderr-  args <- getArgs-  case args of-    src : _ : dst : opts -> do-      Config{..} <- parseOpts def (map toText opts)--      let scanRoot-            | isAbsolute cScanRoot = cScanRoot-            | otherwise = takeDirectory src </> cScanRoot-      validRoot <- Dir.doesDirectoryExist scanRoot-      unless validRoot $-        die $ "Specified scan root is not an existing directory: " <> scanRoot-      contracts <- findContracts cDebug scanRoot--      verifyContractDecls contracts-      let output = fmt @Text $ unlinesF-            [ pragmasSection-            , "module " +| cModuleName |+ " (contracts) where"-            , ""-            , importsSection contracts-            , ""-            , contractsMapSection contracts-            ]-      printDebug cDebug . fmt $-        "Generated module:\n" +| indentF 2 (build output) |+ ""--      writeFileUtf8 dst output-    _ -> do-      die "Usage: lorentz-discover src _ dst moduleName"--newtype IsDebug = IsDebug Bool--data Config = Config-  { cModuleName :: Text-  , cDebug :: IsDebug-  , cScanRoot :: FilePath-  }--instance Default Config where-  def = Config-    { cModuleName = "Main"-    , cDebug = IsDebug False-    , cScanRoot = "."-    }--parseOpts :: Config -> [Text] -> IO Config-parseOpts cfg = \case-  [] -> pure cfg-  "--debug" : opts ->-    parseOpts cfg{ cDebug = IsDebug True } opts-  "--generated-module" : opts ->-    case opts of-      [] -> die "Usage: `--generated-module <module name>`"-      modName : os -> parseOpts cfg{ cModuleName = modName } os-  "--root" : opts ->-    case opts of-      [] -> die "Usage: `--root <directory>`"-      root : os -> parseOpts cfg{ cScanRoot = toString root } os-  opt : _ ->-    die $ "Unknown option: " <> show opt--printDebug :: IsDebug -> Text -> IO ()-printDebug (IsDebug isDebug)-  | isDebug = hPutStrLn stderr . ("contract-discover: " <>)-  | otherwise = \_ -> pass--findContracts :: IsDebug -> FilePath -> IO [ExportedContractInfo]-findContracts isDebug path = do-  isDir <- Dir.doesDirectoryExist path-  if isDir-    then do-      dirs <- Dir.listDirectory path-      concatMapM (findContracts isDebug) (map (path </>) dirs)-    else do-      if isHaskellModule path-        then parseHaskellModule isDebug path-        else pure []--parseHaskellModule :: IsDebug -> FilePath -> IO [ExportedContractInfo]-parseHaskellModule isDebug path = do-  file <- readFileUtf8 path-  case runParser haskellExportsParser path file of-    -- Some autogenerated modules may have no export list, we ignore them-    Left err -> do-      printDebug isDebug . toText $ errorBundlePretty err-      return []-    Right res -> do-      printDebug isDebug $ "In module " +|| path ||+ " found contracts "-                         +| listF' (build . ecdName . eciContractDecl) res |+ ""-      return res---- | Ensures that:------ 1. No two contracts have the same name.-verifyContractDecls :: [ExportedContractInfo] -> IO ()-verifyContractDecls contracts = do-  let vars = map (ecdVar . eciContractDecl) contracts-  let dups = map head . mapMaybe (nonEmpty . Unsafe.init) . group $ sort vars-  case dups of-    [] -> pass-    dup : _ -> die $ "Found multiple contracts with the same name: " <> show dup--pragmasSection :: Builder-pragmasSection =-  mconcat . map (<> "\n") $-  [ "{-# LANGUAGE ImplicitPrelude #-}"-  ]--importsSection :: [ExportedContractInfo] -> Builder-importsSection =-  mconcat . map (<> "\n") .-  (extraImports ++) . map mkImport . ordNub . map eciModuleName-  where-  mkImport m = "import qualified " +| m |+ ""-  extraImports =-    [ "import Data.Text (Text)"-    , "import qualified Data.Map as Map"--    , "import qualified Michelson.Untyped as U"-    , "import Lorentz.Discover"-    ]--contractsMapSection :: [ExportedContractInfo] -> Builder-contractsMapSection contracts =-  "contracts :: Map.Map Text U.Contract\n\-  \contracts = Map.fromList\n  " <> listF' contractPairF contracts-  where-    -- Forms @(contract name, contract variable)@ pair.-    contractPairF ExportedContractInfo{..} =-      let ExportedContractDecl{..} = eciContractDecl-          var = "toUntypedContract " +| eciModuleName |+ "." +| ecdVar |+ ""-      in "\n  (\"" +| ecdName |+ "\", " +| var +| ")"
morley.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 8457691bdf7fc43270f283f6722fc1c2dbc40a1cbc9cf90d3f2724657b6f62bf+-- hash: 341e0aff6cea56ed81fb3488e1f28073f9d4b8ee8f16cb92cd8da89994761071  name:           morley-version:        0.3.0.1+version:        0.4.0 synopsis:       Developer tools for the Michelson Language description:    A library to make writing smart contracts in Michelson — the smart contract language of the Tezos blockchain — pleasant and effective. category:       Language@@ -35,27 +35,57 @@       Lorentz.Arith       Lorentz.Base       Lorentz.Coercions+      Lorentz.Common       Lorentz.Constraints-      Lorentz.Discover+      Lorentz.Doc+      Lorentz.EntryPoints+      Lorentz.EntryPoints.Doc       Lorentz.Errors+      Lorentz.Errors.Common+      Lorentz.Errors.Numeric       Lorentz.Ext+      Lorentz.Extensible       Lorentz.Instr       Lorentz.Macro+      Lorentz.Pack       Lorentz.Polymorphic       Lorentz.Prelude+      Lorentz.Print       Lorentz.Rebinded       Lorentz.Referenced+      Lorentz.Run       Lorentz.Store+      Lorentz.StoreClass       Lorentz.Test+      Lorentz.Test.Consumer       Lorentz.Test.Integrational+      Lorentz.TestScenario+      Lorentz.UParam+      Lorentz.UStore+      Lorentz.UStore.Common+      Lorentz.UStore.Haskell+      Lorentz.UStore.Instances+      Lorentz.UStore.Instr+      Lorentz.UStore.Lift+      Lorentz.UStore.Migration+      Lorentz.UStore.Migration.Base+      Lorentz.UStore.Migration.Batching+      Lorentz.UStore.Migration.Blocks+      Lorentz.UStore.Migration.Diff+      Lorentz.UStore.Types       Lorentz.Value-      Michelson.EqParam+      Lorentz.Zip+      Michelson.Analyzer+      Michelson.Doc       Michelson.ErrorPos+      Michelson.FailPattern       Michelson.Interpret       Michelson.Interpret.Pack       Michelson.Interpret.Unpack       Michelson.Let       Michelson.Macro+      Michelson.OpSize+      Michelson.Optimizer       Michelson.Parser       Michelson.Parser.Annotations       Michelson.Parser.Error@@ -68,6 +98,7 @@       Michelson.Parser.Type       Michelson.Parser.Types       Michelson.Parser.Value+      Michelson.Preprocess       Michelson.Printer       Michelson.Printer.Util       Michelson.Runtime@@ -95,19 +126,23 @@       Michelson.Typed.Arith       Michelson.Typed.Convert       Michelson.Typed.CValue+      Michelson.Typed.Doc+      Michelson.Typed.EntryPoints       Michelson.Typed.Extract       Michelson.Typed.Haskell+      Michelson.Typed.Haskell.Doc       Michelson.Typed.Haskell.Instr       Michelson.Typed.Haskell.Instr.Helpers       Michelson.Typed.Haskell.Instr.Product       Michelson.Typed.Haskell.Instr.Sum+      Michelson.Typed.Haskell.LooseSum       Michelson.Typed.Haskell.Value       Michelson.Typed.Instr       Michelson.Typed.Polymorphic-      Michelson.Typed.Print       Michelson.Typed.Scope       Michelson.Typed.Sing       Michelson.Typed.T+      Michelson.Typed.Util       Michelson.Typed.Value       Michelson.Untyped       Michelson.Untyped.Aliases@@ -120,17 +155,27 @@       Tezos.Address       Tezos.Core       Tezos.Crypto+      Tezos.Crypto.Ed25519+      Tezos.Crypto.Hash+      Tezos.Crypto.P256+      Tezos.Crypto.Secp256k1+      Tezos.Crypto.Util       Util.Alternative       Util.Default       Util.Generic       Util.Instances       Util.IO       Util.Lens+      Util.Markdown       Util.Named       Util.Peano+      Util.Positive       Util.Test.Arbitrary       Util.Test.Ingredients+      Util.Text       Util.Type+      Util.Typeable+      Util.TypeLits       Util.TypeTuple       Util.TypeTuple.Class       Util.TypeTuple.Instances@@ -140,7 +185,7 @@   hs-source-dirs:       src   default-extensions: ApplicativeDo AllowAmbiguousTypes BangPatterns ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable EmptyCase FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MonadFailDesugaring MultiParamTypeClasses MultiWayIf NamedFieldPuns NegativeLiterals NumDecimals OverloadedLabels OverloadedStrings PatternSynonyms PolyKinds QuasiQuotes RankNTypes RecordWildCards RecursiveDo ScopedTypeVariables StandaloneDeriving TemplateHaskell TupleSections TypeApplications TypeFamilies TypeOperators UndecidableInstances ViewPatterns-  ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-implicit-prelude+  ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-implicit-prelude -O0   build-depends:       QuickCheck     , aeson@@ -149,18 +194,21 @@     , base-noprelude >=4.7 && <5     , base16-bytestring     , base58-bytestring+    , bimap     , binary     , bytestring-    , constraints+    , constraints >=0.11     , containers     , cryptonite     , data-default-    , filepath+    , first-class-families >=0.5.0.0     , fmt     , formatting     , ghc-prim+    , gitrev     , hex-text     , hspec+    , interpolate     , lens     , megaparsec >=7.0.0     , memory@@ -168,42 +216,26 @@     , mtl     , named     , parser-combinators >=1.0.0+    , pretty-terminal     , quickcheck-arbitrary-adt     , quickcheck-instances+    , show-type     , singletons     , syb     , tasty     , tasty-ant-xml+    , tasty-hunit     , template-haskell     , text     , time     , timerep     , transformers-compat ==0.6.5+    , unordered-containers     , vector     , vinyl     , wl-pprint-text   default-language: Haskell2010 -executable contract-discover-  main-is: Main.hs-  other-modules:-      Paths_morley-  hs-source-dirs:-      contract-discover-  default-extensions: ApplicativeDo AllowAmbiguousTypes BangPatterns ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable EmptyCase FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MonadFailDesugaring MultiParamTypeClasses MultiWayIf NamedFieldPuns NegativeLiterals NumDecimals OverloadedLabels OverloadedStrings PatternSynonyms PolyKinds QuasiQuotes RankNTypes RecordWildCards RecursiveDo ScopedTypeVariables StandaloneDeriving TemplateHaskell TupleSections TypeApplications TypeFamilies TypeOperators UndecidableInstances ViewPatterns-  ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-implicit-prelude-  build-depends:-      base-noprelude >=4.7 && <5-    , data-default-    , directory-    , filepath-    , fmt-    , megaparsec-    , morley-    , morley-prelude-    , text-  default-language: Haskell2010- executable morley   main-is: Main.hs   other-modules:@@ -213,7 +245,7 @@   hs-source-dirs:       app   default-extensions: ApplicativeDo AllowAmbiguousTypes BangPatterns ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable EmptyCase FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MonadFailDesugaring MultiParamTypeClasses MultiWayIf NamedFieldPuns NegativeLiterals NumDecimals OverloadedLabels OverloadedStrings PatternSynonyms PolyKinds QuasiQuotes RankNTypes RecordWildCards RecursiveDo ScopedTypeVariables StandaloneDeriving TemplateHaskell TupleSections TypeApplications TypeFamilies TypeOperators UndecidableInstances ViewPatterns-  ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-implicit-prelude+  ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-implicit-prelude -O0   build-depends:       base-noprelude >=4.7 && <5     , fmt@@ -228,31 +260,58 @@   type: exitcode-stdio-1.0   main-is: Main.hs   other-modules:+      Test.Analyzer       Test.CValConversion+      Test.Doc+      Test.EntryPoints       Test.Ext+      Test.Integrational       Test.Interpreter-      Test.Interpreter.A1.Feather+      Test.Interpreter.Auction       Test.Interpreter.CallSelf       Test.Interpreter.Compare       Test.Interpreter.Conditionals       Test.Interpreter.ContractOp       Test.Interpreter.EnvironmentSpec       Test.Interpreter.StringCaller-      Test.Lorentz.Discovery+      Test.Lorentz.Base+      Test.Lorentz.DeadCode+      Test.Lorentz.EntryPoints+      Test.Lorentz.Errors+      Test.Lorentz.Extensible       Test.Lorentz.Macro+      Test.Lorentz.Print+      Test.Lorentz.UParam+      Test.Lorentz.UStore.Behaviour+      Test.Lorentz.UStore.Migration.Batched+      Test.Lorentz.UStore.Migration.Batched.V1+      Test.Lorentz.UStore.Migration.Batched.V2+      Test.Lorentz.UStore.Migration.FillInParts+      Test.Lorentz.UStore.Migration.Simple+      Test.Lorentz.UStore.Migration.Simple.V1+      Test.Lorentz.UStore.Migration.Simple.V2+      Test.Lorentz.UStore.SafeLift+      Test.Lorentz.UStore.SafeLift.Helpers       Test.Macro       Test.Michelson.Runtime       Test.Michelson.Text+      Test.Michelson.Typed.Util+      Test.OpSize+      Test.Optimizer       Test.Parser+      Test.Preprocess       Test.Printer.Michelson       Test.Serialization.Aeson       Test.Serialization.Michelson       Test.Tasty.HUnit       Test.Tezos.Address+      Test.Tezos.Core       Test.Tezos.Crypto+      Test.Tezos.Crypto.Hash       Test.Typecheck       Test.Untyped.Instr       Test.Util.Contracts+      Test.Util.HUnit       Test.Util.Parser       Test.Util.QuickCheck       Test.ValConversion@@ -261,7 +320,7 @@   hs-source-dirs:       test   default-extensions: ApplicativeDo AllowAmbiguousTypes BangPatterns ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable EmptyCase FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MonadFailDesugaring MultiParamTypeClasses MultiWayIf NamedFieldPuns NegativeLiterals NumDecimals OverloadedLabels OverloadedStrings PatternSynonyms PolyKinds QuasiQuotes RankNTypes RecordWildCards RecursiveDo ScopedTypeVariables StandaloneDeriving TemplateHaskell TupleSections TypeApplications TypeFamilies TypeOperators UndecidableInstances ViewPatterns DerivingStrategies-  ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-implicit-prelude -threaded -with-rtsopts=-N+  ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-implicit-prelude -O0 -threaded -with-rtsopts=-N   build-tool-depends:       tasty-discover:tasty-discover   build-depends:@@ -269,14 +328,15 @@     , QuickCheck     , aeson     , base-noprelude >=4.7 && <5+    , bimap     , bytestring+    , constraints     , containers     , data-default     , directory     , filepath     , fmt     , formatting-    , generic-arbitrary     , hex-text     , hspec     , hspec-expectations@@ -284,14 +344,15 @@     , megaparsec >=7.0.0     , morley     , morley-prelude-    , mtl-    , qm-interpolated-string     , quickcheck-arbitrary-adt     , quickcheck-instances     , singletons+    , spoon     , syb     , tasty     , tasty-hspec     , tasty-quickcheck     , text+    , unordered-containers+    , vinyl   default-language: Haskell2010
src/Lorentz.hs view
@@ -6,14 +6,26 @@ import Lorentz.Arith as Exports import Lorentz.Base as Exports import Lorentz.Coercions as Exports+import Lorentz.Common as Exports import Lorentz.Constraints as Exports+import Lorentz.Doc as Exports+import Lorentz.EntryPoints as Exports+import Lorentz.EntryPoints.Doc as Exports import Lorentz.Errors as Exports+import Lorentz.Errors.Common as Exports ()+import Lorentz.Errors.Numeric as Exports import Lorentz.Ext as Exports import Lorentz.Instr as Exports import Lorentz.Macro as Exports+import Lorentz.Pack as Exports import Lorentz.Polymorphic as Exports import Lorentz.Prelude as Exports+import Lorentz.Print as Exports import Lorentz.Rebinded as Exports import Lorentz.Referenced as Exports-import Lorentz.Store as Exports+import Lorentz.Run as Exports+import Lorentz.StoreClass as Exports+import Lorentz.UParam as Exports+import Lorentz.UStore as Exports import Lorentz.Value as Exports+import Lorentz.Zip as Exports ()
src/Lorentz/ADT.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE FunctionalDependencies #-}+ module Lorentz.ADT   ( HasField   , HasFieldOfType@@ -16,7 +18,10 @@   , wrap_   , case_   , caseT-  , (/->)+  , unwrapUnsafe_+  , CaseTC+  , CaseArrow (..)+  , CaseClauseL (..)   , InstrConstructC   , ConstructorFieldTypes @@ -25,6 +30,8 @@   , (:!)   , (:?)   , arg+  , argDef+  , argF   ) where  import Data.Constraint (Dict(..))@@ -32,7 +39,7 @@ import Data.Vinyl.Core (RMap(..), Rec(..)) import Data.Vinyl.Derived (Label) import GHC.TypeLits (AppendSymbol, Symbol)-import Named ((:!), (:?), arg)+import Named ((:!), (:?), arg, argDef, argF)  import Lorentz.Base import Lorentz.Coercions@@ -56,6 +63,7 @@ -- | A pair of field name and type. data NamedField = NamedField Symbol Kind.Type type n := ty = 'NamedField n ty+infixr 0 :=  -- | Shortcut for multiple 'HasFieldOfType' constraints. type family HasFieldsOfType (dt :: Kind.Type) (fs :: [NamedField])@@ -146,8 +154,10 @@ constructT = construct . recFromTuple  -- | Lift an instruction to field constructor.-fieldCtor :: (st :-> f & st) -> FieldConstructor st f-fieldCtor (I i) = FieldConstructor i+fieldCtor :: HasCallStack => (st :-> f & st) -> FieldConstructor st f+fieldCtor = \case+  I i -> FieldConstructor i+  FI _ -> error "Field constructor always fails"  -- | Wrap entry in constructor. Useful for sum types. wrap_@@ -162,21 +172,25 @@ data CaseClauseL (inp :: [Kind.Type]) (out :: [Kind.Type]) (param :: CaseClauseParam) where   CaseClauseL :: AppendCtorField x inp :-> out -> CaseClauseL inp out ('CaseClauseParam ctor x) --- | Lift an instruction to case clause.------ You should write out constructor name corresponding to the clause--- explicitly. Prefix constructor name with "c" letter, otherwise--- your label will not be recognized by Haskell parser.--- Passing constructor name can be circumvented but doing so is not recomended--- as mentioning contructor name improves readability and allows avoiding--- some mistakes.-(/->)-  :: Label ("c" `AppendSymbol` ctor)-  -> AppendCtorField x inp :-> out-  -> CaseClauseL inp out ('CaseClauseParam ctor x)-(/->) _ = CaseClauseL-infixr 0 /->+-- | Provides "case" arrow which works on different wrappers for clauses.+class CaseArrow name body clause | clause -> name, clause -> body where+  -- | Lift an instruction to case clause.+  --+  -- You should write out constructor name corresponding to the clause+  -- explicitly. Prefix constructor name with "c" letter, otherwise+  -- your label will not be recognized by Haskell parser.+  -- Passing constructor name can be circumvented but doing so is not recomended+  -- as mentioning contructor name improves readability and allows avoiding+  -- some mistakes.+  (/->) :: Label name -> body -> clause+  infixr 0 /-> +instance ( name ~ ("c" `AppendSymbol` ctor)+         , body ~ (AppendCtorField x inp :-> out)+         ) => CaseArrow name body+                (CaseClauseL inp out ('CaseClauseParam ctor x)) where+  (/->) _ = CaseClauseL+ -- | Pattern match on the given sum type. -- -- You have to provide a 'Rec' containing case branches.@@ -187,23 +201,40 @@      , RMap (CaseClauses dt)      )   => Rec (CaseClauseL inp out) (CaseClauses dt) -> dt & inp :-> out-case_ = I . instrCase @dt . rmap coerceCaseClause+case_ = LorentzInstr . instrCase @dt . rmap coerceCaseClause   where     coerceCaseClause       :: forall clauses.          CaseClauseL inp out clauses -> CaseClause (ToTs inp) (ToTs out) clauses-    coerceCaseClause (CaseClauseL (I cc)) =+    coerceCaseClause (CaseClauseL (LorentzInstr cc)) =       CaseClause $ case Proxy @clauses of         (_ :: Proxy ('CaseClauseParam ctor cc)) ->           case appendCtorFieldAxiom @cc @inp of Dict -> cc  -- | Like 'case_', accepts a tuple of clauses, which may be more convenient.+--+-- If user is experiencing problems with wierd errors about tuples while using+-- this function, he should take look at `Util.TypeTuple.Instances` and ensure+-- that his tuple isn't bigger than generated instances, if so, he should probably+-- extend number of generated instances. caseT   :: forall dt out inp clauses.-     ( InstrCaseC dt inp out-     , RMap (CaseClauses dt)-     , RecFromTuple clauses-     , clauses ~ Rec (CaseClauseL inp out) (CaseClauses dt)-     )+     CaseTC dt out inp clauses   => IsoRecTuple clauses -> dt & inp :-> out caseT = case_ @dt . recFromTuple++type CaseTC dt out inp clauses =+  ( InstrCaseC dt inp out+  , RMap (CaseClauses dt)+  , RecFromTuple clauses+  , clauses ~ Rec (CaseClauseL inp out) (CaseClauses dt)+  )++-- | Wrap entry in constructor. Useful for sum types.+unwrapUnsafe_+  :: forall dt name st.+     InstrUnwrapC dt name+  => Label name -> dt & st :-> (CtorOnlyField name dt ': st)+unwrapUnsafe_ =+  case appendCtorFieldAxiom @(GetCtorField dt name) @st of+    Dict -> I . instrUnwrapUnsafe @dt
src/Lorentz/Arith.hs view
@@ -1,6 +1,7 @@ -- | Type families from 'Michelson.Typed.Arith' lifted to Haskell types. module Lorentz.Arith   ( ArithOpHs (..)+  , CompareOpHs   , UnaryArithOpHs (..)   ) where @@ -108,24 +109,20 @@ instance UnaryArithOpHs Not Bool where   type UnaryArithResHs Not Bool = Bool -instance ArithOpHs Compare Bool Bool where-  type ArithResHs Compare Bool Bool = Integer-instance ArithOpHs Compare Address Address where-  type ArithResHs Compare Address Address = Integer-instance ArithOpHs Compare Natural Natural where-  type ArithResHs Compare Natural Natural = Integer-instance ArithOpHs Compare Integer Integer where-  type ArithResHs Compare Integer Integer = Integer-instance ArithOpHs Compare MText MText where-  type ArithResHs Compare MText MText = Integer-instance ArithOpHs Compare ByteString ByteString where-  type ArithResHs Compare ByteString ByteString = Integer-instance ArithOpHs Compare Timestamp Timestamp where-  type ArithResHs Compare Timestamp Timestamp = Integer-instance ArithOpHs Compare Mutez Mutez where-  type ArithResHs Compare Mutez Mutez = Integer-instance ArithOpHs Compare KeyHash KeyHash where-  type ArithResHs Compare KeyHash KeyHash = Integer+class (Typeable (ToCT n), IsComparable n, CompareOp (ToCT n)) =>+      CompareOpHs n+instance (n ~ m, CompareOpHs n) => ArithOpHs Compare n m where+  type ArithResHs Compare n m = Integer+instance CompareOpHs Bool+instance CompareOpHs Address+instance CompareOpHs EpAddress+instance CompareOpHs Natural+instance CompareOpHs Integer+instance CompareOpHs MText+instance CompareOpHs ByteString+instance CompareOpHs Timestamp+instance CompareOpHs Mutez+instance CompareOpHs KeyHash  instance UnaryArithOpHs Eq' Integer where   type UnaryArithResHs Eq' Integer = Bool
src/Lorentz/Base.hs view
@@ -1,4 +1,5 @@ {-# OPTIONS_GHC -Wno-redundant-constraints #-}+{-# LANGUAGE DerivingStrategies #-}  -- | Foundation of Lorentz development. module Lorentz.Base@@ -6,69 +7,164 @@   , type (%>)   , type (&)   , (#)+  , pattern I+  , pattern FI+  , iGenericIf+  , iAnyCode+  , iNonFailingCode+  , iMapAnyCode -  , compileLorentz-  , compileLorentzContract-  , printLorentzContract+  , parseLorentzValue+  , transformStringsLorentz+  , transformBytesLorentz+  , optimizeLorentz+  , optimizeLorentzWithConf    , ContractOut   , Contract+  , SomeContract (..)   , Lambda-   ) where +import Data.Default (def) import qualified Data.Kind as Kind-import Data.Singletons (SingI)+import Data.Singletons (SingI(..))+import Fmt (Buildable(..))  import Lorentz.Constraints import Lorentz.Value-import Michelson.Printer (printTypedContract)-import Michelson.Typed (Instr(..), T(..), ToT, ToTs, Value'(..))+import Michelson.ErrorPos (InstrCallStack)+import Michelson.Optimizer (OptimizerConf, optimizeWithConf)+import Michelson.Parser (ParserException, parseExpandValue)+import Michelson.Preprocess (transformBytes, transformStrings)+import Michelson.TypeCheck (TCError, runTypeCheckIsolated, typeVerifyValue)+import Michelson.Typed+  (Instr(..), RemFail(..), ToT, ToTs, Value, rfAnyInstr, rfMapAnyInstr, rfMerge)+import qualified Michelson.Untyped as U  -- | Alias for instruction which hides inner types representation via 'T'.-newtype (inp :: [Kind.Type]) :-> (out :: [Kind.Type]) =-  I { unI :: Instr (ToTs inp) (ToTs out) }-  deriving (Show, Eq)+newtype (inp :: [Kind.Type]) :-> (out :: [Kind.Type]) = LorentzInstr+  { unLorentzInstr :: RemFail Instr (ToTs inp) (ToTs out)+  } deriving (Show, Eq) infixr 1 :-> +instance Semigroup (s :-> s) where+  (<>) = (#)+instance Monoid (s :-> s) where+  mempty = I Nop++pattern I :: Instr (ToTs inp) (ToTs out) -> inp :-> out+pattern I i = LorentzInstr (RfNormal i)++pattern FI :: (forall out'. Instr (ToTs inp) out') -> inp :-> out+pattern FI i = LorentzInstr (RfAlwaysFails i)++{-# COMPLETE I, FI #-}++iGenericIf+  :: (forall s'. Instr (ToTs a) s' -> Instr (ToTs b) s' -> Instr (ToTs c) s')+  -> (a :-> s) -> (b :-> s) -> (c :-> s)+iGenericIf merger (LorentzInstr instr1) (LorentzInstr instr2) =+  LorentzInstr (rfMerge merger instr1 instr2)++iAnyCode :: inp :-> out -> Instr (ToTs inp) (ToTs out)+iAnyCode = rfAnyInstr . unLorentzInstr++iNonFailingCode :: HasCallStack => inp :-> out -> Instr (ToTs inp) (ToTs out)+iNonFailingCode (I i) = i+iNonFailingCode (FI _) = error "Always failing code cannot appear here"++iMapAnyCode+  :: (forall o'. Instr (ToTs i1) o' -> Instr (ToTs i2) o')+  -> (i1 :-> o)+  -> (i2 :-> o)+iMapAnyCode f (LorentzInstr i) = LorentzInstr $ rfMapAnyInstr f i++-- There is also @instance IsoValue (i :-> o)@ in a separate module.+ -- | Alias for ':->', seems to make signatures more readable sometimes. -- -- Let's someday decide which one of these two should remain. type (%>) = (:->) infixr 1 %> --- | For use outside of Lorentz.-compileLorentz :: (inp :-> out) -> Instr (ToTs inp) (ToTs out)-compileLorentz = unI- type ContractOut st = '[([Operation], st)] type Contract cp st = '[(cp, st)] :-> ContractOut st --- | Version of 'compileLorentz' specialized to instruction corresponding to--- contract code.-compileLorentzContract-  :: forall cp st.-     (NoOperation cp, NoOperation st, NoBigMap cp, CanHaveBigMap st)-  => Contract cp st -> Instr '[ToT (cp, st)] '[ToT ([Operation], st)]-compileLorentzContract = compileLorentz--printLorentzContract-  :: forall cp st.-      ( SingI (ToT cp), SingI (ToT st)-      , NoOperation cp, NoOperation st, NoBigMap cp, CanHaveBigMap st-      )-  => Contract cp st -> LText-printLorentzContract = printTypedContract . compileLorentzContract+data SomeContract where+  SomeContract+    :: (NiceParameter cp, NiceStorage st)+    => Contract cp st+    -> SomeContract  type (&) (a :: Kind.Type) (b :: [Kind.Type]) = a ': b infixr 2 &  (#) :: (a :-> b) -> (b :-> c) -> a :-> c I l # I r = I (l `Seq` r)+I l # FI r = FI (l `Seq` r)+FI l # _ = FI l+infixl 8 #  type Lambda i o = '[i] :-> '[o] -instance IsoValue (Lambda inp out) where-  type ToT (Lambda inp out) = 'TLambda (ToT inp) (ToT out)-  toVal = VLam . unI-  fromVal (VLam l) = I l+-- | Errors that can happen during parsing into a Lorentz value.+data ParseLorentzError+  = ParseLorentzParseError !ParserException+  | ParseLorentzTypecheckError !TCError+  deriving stock (Show, Eq)++instance Buildable ParseLorentzError where+  build =+    \case+      ParseLorentzParseError e -> build e+      ParseLorentzTypecheckError e -> build e++-- | Parse textual representation of a Michelson value and turn it+-- into corresponding Haskell value.+--+-- Note: it won't work in some complex cases, e. g. if there is a+-- lambda which uses an instruction which depends on current+-- contract's type. Obviously it can not work, because we don't have+-- any information about a contract to which this value belongs (there+-- is no such contract at all).+parseLorentzValue ::+     forall v. (IsoValue v, SingI (ToT v), Typeable (ToT v))+  => Text+  -> Either ParseLorentzError v+parseLorentzValue =+  fmap fromVal . (toTyped <=< first ParseLorentzParseError . parseExpandValue)+  where+    toTyped :: U.Value -> Either ParseLorentzError (Value (ToT v))+    toTyped =+      first ParseLorentzTypecheckError .+      runTypeCheckIsolated .+      usingReaderT (def @InstrCallStack) .+      typeVerifyValue++-- | Lorentz version of 'transformStrings'.+transformStringsLorentz ::+  Bool -> (MText -> MText) -> inp :-> out -> inp :-> out+transformStringsLorentz goToValues f =+  iMapAnyCode $ transformStrings goToValues f++-- | Lorentz version of 'transformBytes'.+transformBytesLorentz ::+  Bool -> (ByteString -> ByteString) -> inp :-> out -> inp :-> out+transformBytesLorentz goToValues f =+  iMapAnyCode $ transformBytes goToValues f++optimizeLorentzWithConf+  :: OptimizerConf+  -> inp :-> out+  -> inp :-> out+optimizeLorentzWithConf conf =+  -- Optimizer can produce dead code.+  -- Example: @push True # if_ failWith nop # ...@ will fold to @failWith # ...@.+  -- But let's not care about this case for now until need in it fires.+  iMapAnyCode (optimizeWithConf conf)++optimizeLorentz+  :: inp :-> out+  -> inp :-> out+optimizeLorentz = optimizeLorentzWithConf def
src/Lorentz/Coercions.hs view
@@ -2,12 +2,18 @@ module Lorentz.Coercions   ( Coercible_   , coerce_+  , gcoerce_+  , fakeCoerce    , coerceUnwrap   , coerceWrap   , toNamed   , fromNamed +    -- * Coercions for some basic types+  , futureContract+  , unFutureContract+     -- * Re-exports   , Wrapped (..)   ) where@@ -17,6 +23,8 @@ import Named (NamedF)  import Lorentz.Base+import Lorentz.Instr+import Lorentz.Value import Michelson.Typed  -- | Whether two types have the same Michelson representation.@@ -26,6 +34,13 @@ coerce_ :: Coercible_ a b => a & s :-> b & s coerce_ = I Nop +gcoerce_ :: Coercible_ (t a) (t b) => t a : s :-> t b : s+gcoerce_ = coerce_++-- | Convert between two stacks via failing.+fakeCoerce :: s1 :-> s2+fakeCoerce = unit # I FAILWITH+ -- | Specialized version of 'coerce_' to wrap into a haskell newtype. coerceWrap   :: Coercible_ newtyp (Unwrapped newtyp)@@ -45,3 +60,15 @@ -- | Unpack named value. fromNamed :: Label name -> NamedF Identity a name : s :-> a : s fromNamed _ = coerceUnwrap++----------------------------------------------------------------------------+-- Coercions for some basic types+----------------------------------------------------------------------------++-- | Make up a 'FutureContract'.+futureContract :: Address : s :-> FutureContract p : s+futureContract = coerce_++-- | Get address referred by 'FutureContract'.+unFutureContract :: FutureContract p : s :-> Address : s+unFutureContract = coerce_
+ src/Lorentz/Common.hs view
@@ -0,0 +1,17 @@+-- | Common primitives.+module Lorentz.Common+  ( Entrypoint+  , Entrypoint_+  ) where++import Lorentz.Base++-- | Single entrypoint of a contract.+--+-- Note that we cannot make it return @[[Operation], store]@ because+-- such entrypoint should've been followed by @pair@, and this is not+-- possible if entrypoint implementation ends with 'failWith'.+type Entrypoint param store = '[ param, store ] :-> ContractOut store++-- | Version of 'Entrypoint' which accepts no argument.+type Entrypoint_ store = '[ store ] :-> ContractOut store
src/Lorentz/Constraints.hs view
@@ -1,23 +1,98 @@+{-# LANGUAGE UndecidableSuperClasses #-}++-- | Scope-related constraints used in Lorentz. module Lorentz.Constraints-  ( CanHaveBigMap+  ( -- * Grouped constraints+    NiceParameter+  , NiceStorage+  , NiceConstant+  , NicePackedValue+  , NiceUnpackedValue+  , NiceFullPackedValue+  , NicePrintedValue++  , niceParameterEvi+  , niceStorageEvi+  , niceConstantEvi+  , nicePackedValueEvi+  , niceUnpackedValueEvi+  , nicePrintedValueEvi++    -- * Individual constraints (internals)+  , CanHaveBigMap   , KnownValue   , KnownCValue   , NoOperation+  , NoContractType   , NoBigMap++  , -- * Re-exports+    withDict   ) where +import Data.Constraint (trans, weaken2) import Data.Singletons (SingI)  import Michelson.Typed +-- We write these constraints as class + instance, rather than+-- type aliases, in order to allow their partial application.+ -- | Gathers constraints, commonly required for values.-type KnownValue a = (Typeable (ToT a), SingI (ToT a))+class (IsoValue a, Typeable (ToT a), SingI (ToT a)) => KnownValue a+instance (IsoValue a, Typeable (ToT a), SingI (ToT a)) => KnownValue a -type KnownCValue a = (IsoValue a, Typeable (ToCT a), SingI (ToCT a))+class (IsoValue a, Typeable (ToCT a), SingI (ToCT a)) => KnownCValue a+instance (IsoValue a, Typeable (ToCT a), SingI (ToCT a)) => KnownCValue a  -- | Ensure given type does not contain "operation".-type NoOperation a = ForbidOp (ToT a)+class (IsoValue a, ForbidOp (ToT a)) => NoOperation a+instance (IsoValue a, ForbidOp (ToT a)) => NoOperation a -type NoBigMap a = ForbidBigMap (ToT a)+class (IsoValue a, ForbidContract (ToT a)) => NoContractType a+instance (IsoValue a, ForbidContract (ToT a)) => NoContractType a -type CanHaveBigMap a = AllowBigMap (ToT a)+class (IsoValue a, ForbidBigMap (ToT a)) => NoBigMap a+instance (IsoValue a, ForbidBigMap (ToT a)) => NoBigMap a++class (IsoValue a, HasNoNestedBigMaps (ToT a)) => CanHaveBigMap a+instance (IsoValue a, HasNoNestedBigMaps (ToT a)) => CanHaveBigMap a++-- | Constraint applied to parameter type.+type NiceParameter a = (KnownValue a, ProperParameterBetterErrors (ToT a))++type NiceStorage a = (KnownValue a, ProperStorageBetterErrors (ToT a))++type NiceConstant a = (KnownValue a, ProperConstantBetterErrors (ToT a))++type NicePackedValue a = (KnownValue a, ProperPackedValBetterErrors (ToT a))++type NiceUnpackedValue a = (KnownValue a, ProperUnpackedValBetterErrors (ToT a))++type NiceFullPackedValue a = (NicePackedValue a, NiceUnpackedValue a)++type NicePrintedValue a = (KnownValue a, ProperPrintedValBetterErrors (ToT a))++niceParameterEvi :: forall a. NiceParameter a :- ParameterScope (ToT a)+niceParameterEvi =+  properParameterEvi @(ToT a) `trans` weaken2++niceStorageEvi :: forall a. NiceStorage a :- StorageScope (ToT a)+niceStorageEvi =+  properStorageEvi @(ToT a) `trans` weaken2++niceConstantEvi :: forall a. NiceConstant a :- ConstantScope (ToT a)+niceConstantEvi =+  properConstantEvi @(ToT a) `trans` weaken2++nicePackedValueEvi :: forall a. NicePackedValue a :- PackedValScope (ToT a)+nicePackedValueEvi =+  properPackedValEvi @(ToT a) `trans` weaken2++niceUnpackedValueEvi :: forall a. NiceUnpackedValue a :- UnpackedValScope (ToT a)+niceUnpackedValueEvi =+  properUnpackedValEvi @(ToT a) `trans` weaken2++nicePrintedValueEvi :: forall a. NicePrintedValue a :- PrintedValScope (ToT a)+nicePrintedValueEvi =+  properPrintedValEvi @(ToT a) `trans` weaken2
− src/Lorentz/Discover.hs
@@ -1,118 +0,0 @@--- | Utilities used for contracts discovery.------ All the discovery logic resides in 'lorentz-discover' executable.-module Lorentz.Discover-  ( IsContract (..)--  , ExportedContractInfo (..)-  , ExportedContractDecl (..)--  , isHaskellModule-  , haskellExportsParser-  ) where--import Data.Char (isAlphaNum)-import Data.Singletons (SingI)-import qualified Data.Text as T-import System.FilePath.Posix (takeExtension, takeFileName)-import Text.Megaparsec (Parsec)-import qualified Text.Megaparsec as P-import qualified Text.Megaparsec.Char as P-import qualified Text.Megaparsec.Char.Lexer as PL--import qualified Lorentz.Base as L-import Lorentz.Constraints-import qualified Michelson.Typed as T-import qualified Michelson.Untyped as U---- | Defined for values representing a contract.-class IsContract c where-  toUntypedContract :: c -> U.Contract--instance IsContract U.Contract where-  toUntypedContract = id--instance (SingI cp, SingI st) => IsContract (T.Contract cp st) where-  toUntypedContract = T.convertContract--instance ( SingI (T.ToT cp), SingI (T.ToT st)-         , NoOperation cp, NoOperation st, NoBigMap cp, CanHaveBigMap st-         ) =>-         IsContract (L.Contract cp st) where-  toUntypedContract = toUntypedContract . L.compileLorentzContract---- | Information about a contract required for contracts registry.-data ExportedContractInfo = ExportedContractInfo-  { eciModuleName :: Text-  , eciContractDecl :: ExportedContractDecl-  } deriving (Show, Eq)---- | Contract names, for Haskell and for humans.-data ExportedContractDecl = ExportedContractDecl-  { ecdName :: Text-    -- ^ Identifier of a contract, e.g. "auction".-  , ecdVar :: Text-    -- ^ Name of a contract as is appears in Haskell code.-  } deriving (Show, Eq)--isHaskellModule :: FilePath -> Bool-isHaskellModule path =-  let file = takeFileName path-  in and-     [ takeExtension file == ".hs"-     , all (\c -> isAlphaNum c || c == '_' || c == '.') file-     ]--haskellExportsParser :: Parsec Void Text [ExportedContractInfo]-haskellExportsParser = do-  space-  symbol "module"-  moduleName <--    lexeme $ P.takeWhile1P (Just "module name")-                           (\c -> isAlphaNum c || c `elem` ['.', '_'])-  symbol "("-  exports <- exportItems-  symbol ")"-  symbol "where"-  return-    [ ExportedContractInfo-      { eciModuleName = moduleName-      , eciContractDecl = decl-      }-    | exportRaw <- exports-    , let export = T.strip exportRaw-    , Just decl <- pure $ toContractDecl export-    ]-  where-    exportItems :: Parsec Void Text [Text]-    exportItems = P.sepBy exportItem (symbol ",")--    -- We do not follow the syntax precisely, just trying to parse-    -- all valid Haskell programs-    exportItem = fmap mconcat . many . lexeme $-      P.choice-        [ P.takeWhile1P Nothing isExportEntryChar-        , do symbol "("-             _ <- exportItems-             symbol ")"-             return "(..)"  -- we are not interested in content-        , symbol ".." $> ".."-        ]--    space = PL.space P.space1 (PL.skipLineComment "--")-                              (PL.skipBlockComment "{-" "-}")-    lexeme = PL.lexeme space-    symbol = void . PL.symbol space--isExportEntryChar :: Char -> Bool-isExportEntryChar c = isAlphaNum c || c == '_'--toContractDecl :: Text -> Maybe ExportedContractDecl-toContractDecl varName = do-  rawName <- T.stripPrefix "contract_" varName-  guard $ all isExportEntryChar $ toString rawName-  let name = T.replace "_" " " rawName-  return ExportedContractDecl-    { ecdName = name-    , ecdVar = varName-    }
+ src/Lorentz/Doc.hs view
@@ -0,0 +1,133 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module Lorentz.Doc+  ( doc+  , docGroup+  , buildLorentzDoc+  , renderLorentzDoc+  , contractName+  , cutLorentzNonDoc++    -- * Re-exports+  , Markdown+  , DocItem (..)+  , docItemPosition+  , DocItemId (..)+  , DocItemPlacementKind (..)+  , DocItemRef (..)+  , DocSectionNameStyle (..)+  , SomeDocItem (..)+  , SomeDocDefinitionItem (..)+  , SubDoc (..)+  , DocGrouping+  , ContractDoc (..)+  , DDescription (..)+  , DVersion (..)+  , DGitRevision (..)+  , GitRepoSettings (..)+  , mkDGitRevision+  , morleyRepoSettings+  , DComment (..)+  , DType (..)+  , docDefinitionRef+  , contractDocToMarkdown+  , subDocToMarkdown++  , TypeHasDoc (..)+  , SomeTypeWithDoc (..)++  , HaveCommonTypeCtor+  , IsHomomorphic+  , genericTypeDocDependencies+  , customTypeDocMdReference+  , homomorphicTypeDocMdReference+  , poly1TypeDocMdReference+  , poly2TypeDocMdReference+  , homomorphicTypeDocHaskellRep+  , concreteTypeDocHaskellRep+  , concreteTypeDocHaskellRepUnsafe+  , haskellRepNoFields+  , haskellRepStripFieldPrefix+  , homomorphicTypeDocMichelsonRep+  , concreteTypeDocMichelsonRep+  , concreteTypeDocMichelsonRepUnsafe+  ) where++import Data.Singletons (demote)++import Lorentz.Base+import Lorentz.Value+import Lorentz.Zip ()+import Michelson.Doc+import Michelson.Optimizer+import Michelson.Typed+import Util.Markdown+import Util.Type++-- | Put a document item.+doc :: DocItem di => di -> s :-> s+doc = I . Ext . DOC_ITEM . SomeDocItem++-- | Group documentation built in the given piece of code+-- into block dedicated to one thing, e.g. to one entry point.+docGroup :: DocGrouping -> (inp :-> out) -> (inp :-> out)+docGroup gr = iMapAnyCode (DocGroup gr)++-- | Give a name to given contract. Apply it to the whole contract code.+contractName :: Text -> (inp :-> out) -> (inp :-> out)+contractName name = docGroup (SomeDocItem . DName name)++buildLorentzDoc :: inp :-> out -> ContractDoc+buildLorentzDoc (iAnyCode -> code) = buildInstrDoc code++renderLorentzDoc :: inp :-> out -> LText+renderLorentzDoc = contractDocToMarkdown . buildLorentzDoc++-- | Leave only instructions related to documentation.+--+-- This function is useful when your method executes a lambda coming from outside,+-- but you know its properties and want to propagate its documentation to your+-- contract code.+cutLorentzNonDoc :: (inp :-> out) -> (s :-> s)+cutLorentzNonDoc (iAnyCode -> code) = I $ cutInstrNonDoc optimize code++instance Each [Typeable, ReifyList TypeHasDoc] [i, o] =>+         TypeHasDoc (i :-> o) where+  typeDocName _ = "Code (extended lambda)"+  typeDocMdReference tp wp =+    let DocItemRef (DocItemId ctorDocItemId) = docItemRef (DType tp)+        refToThis = mdLocalRef (mdTicked "Code") ctorDocItemId+    in applyWithinParens wp $+      mconcat $ intersperse " " [refToThis, refToStack @i, refToStack @o]+    where+    refToStack :: forall s. ReifyList TypeHasDoc s => Markdown+    refToStack =+      let stack = reifyList @_ @TypeHasDoc @s (\p -> typeDocMdReference p (WithinParens False))+      in mconcat+          [ mdBold "["+          , case stack of+              [] -> " "+              st -> mconcat $ intersperse (mdBold "," <> " ") st+          , mdBold "]"+          ]++  typeDocMdDescription =+    "`Code i o` stands for a sequence of instructions which accepts stack \+    \of type `i` and returns stack of type `o`.\n\n\+    \When both `i` and `o` are of length 1, this primitive corresponds to \+    \the Michelson lambda. In more complex cases code is surrounded with `pair`\+    \and `unpair` instructions until fits into mentioned restriction.\+    \"+  typeDocDependencies _ = mconcat+    [ reifyList @_ @TypeHasDoc @i SomeTypeWithDoc+    , reifyList @_ @TypeHasDoc @o SomeTypeWithDoc+    , [ SomeTypeWithDoc (Proxy @Integer)+      , SomeTypeWithDoc (Proxy @Natural)+      , SomeTypeWithDoc (Proxy @MText)+      ]+    ]+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep _ =+    ( Just "Code [Integer, Natural, MText, ()] [ByteString]"+    , demote @(ToT ([Integer, Natural, MText, ()] :-> '[ByteString]))+    )
+ src/Lorentz/EntryPoints.hs view
@@ -0,0 +1,349 @@+{-# LANGUAGE UndecidableSuperClasses #-}++module Lorentz.EntryPoints+  ( ParameterEntryPoints (..)+  , ParameterEntryPointsSplit (..)+  , mapParameterEntryPoints+  , pepNone+  , pepPlain+  , pepRecursive+  ) where++import qualified Data.Kind as Kind+import Data.Singletons (SingI)+import Data.Type.Bool (If)+import qualified GHC.Generics as G+import Named (NamedF)++import Lorentz.Base ((:->))+import Lorentz.Constraints+import Lorentz.Zip+import Michelson.Text+import Michelson.Typed+  (BigMap, ContractRef(..), EpAddress, Notes(..), Operation, T(..), ToT, ToCT,+  starNotes)+import Michelson.Typed.Haskell.Instr.Sum (IsPrimitiveValue)+import Michelson.Typed.Haskell.Value (GValueType, IsGenericIsoValue)+import Michelson.Untyped (Annotation(..), FieldAnn, TypeAnn, ann, noAnn)+import Tezos.Address+import Tezos.Core+import Tezos.Crypto+import Util.Text+import Util.TypeLits++-- | Which entrypoints given parameter declares.+class NiceParameter p => ParameterEntryPoints p where+  parameterEntryPoints :: ParameterEntryPointsSplit p++-- | Implementation of 'parameterEntryPoints'.+newtype ParameterEntryPointsSplit p = ParameterEntryPointsSplit+  { pesNotes :: Notes (ToT p)+    -- ^ Parameter annotations which declare necessary entrypoints.+  }++mapParameterEntryPoints+  :: (ToT a ~ ToT b)+  => (a -> b) -> ParameterEntryPointsSplit a -> ParameterEntryPointsSplit b+mapParameterEntryPoints _ ParameterEntryPointsSplit{..} =+  ParameterEntryPointsSplit{..}++-- | No entrypoints declared, parameter type will serve as argument type+-- of the only existing entrypoint.+pepNone :: SingI (ToT p) => ParameterEntryPointsSplit p+pepNone = ParameterEntryPointsSplit starNotes++instance ParameterEntryPoints () where+  parameterEntryPoints = pepNone++-- Common implementations+----------------------------------------------------------------------------++-- | Fits for case when your contract exposes multiple entrypoints+-- via having sum type as its parameter.+--+-- In particular, this will attach field annotations to immediate parameter "arms"+-- which will be named as corresponding constructor names.+pepPlain :: PesEntryPointsC 'False cp st => ParameterEntryPointsSplit cp+pepPlain = pepEntryPointsExt @'False++-- | Similar to 'pesEntryPoints', but for case of parameter being defined as+-- several nested datatypes.+--+-- In particular, this will traverse sum types recursively, stopping at+-- Michelson primitives (like 'Natural') and constructors with number of+-- fields different from one.+pepRecursive :: PesEntryPointsC 'True cp st => ParameterEntryPointsSplit cp+pepRecursive = pepEntryPointsExt @'True++pepEntryPointsExt+  :: forall deep cp st.+     (PesEntryPointsC deep cp st)+  => ParameterEntryPointsSplit cp+pepEntryPointsExt = ParameterEntryPointsSplit $+  mkEntryPointsNotes @deep @(BuildEPTree deep cp) @cp++type PesEntryPointsC deep cp st =+  ( IsGenericIsoValue cp+  , EntryPointsNotes deep (BuildEPTree deep cp) cp+  , GRequireSumType (G.Rep cp)+  , HasCallStack+  )++-- | Turn constructor name into an appropriate field annotation.+ctorNameToAnn :: HasCallStack => Text -> FieldAnn+ctorNameToAnn = Annotation . headToLower++-- | Ensure that given type is a sum type.+--+-- This helps to prevent attempts to apply a function to, for instance, a pair.+type family GRequireSumType (x :: Kind.Type -> Kind.Type) :: Constraint where+  GRequireSumType (G.M1 _ _ x) = GRequireSumType x+  GRequireSumType (_ G.:+: _) = ()+  GRequireSumType _ = TypeError ('Text "Expected sum type")++-- | Entrypoints tree - skeleton on 'TOr' tree later used to distinguish+-- between constructors-entrypoints and constructors which consolidate+-- a whole pack of entrypoints.+data EPTree+  = EPNode EPTree EPTree+  | EPLeaf++-- | Build 'EPTree' by parameter type.+type BuildEPTree deep a = GBuildEntryPointsTree deep (G.Rep a)++type family GBuildEntryPointsTree (deep :: Bool) (x :: Kind.Type -> Kind.Type)+             :: EPTree where+  GBuildEntryPointsTree deep (G.D1 _ x) =+    GBuildEntryPointsTree deep x+  GBuildEntryPointsTree deep (x G.:+: y) =+    'EPNode (GBuildEntryPointsTree deep x) (GBuildEntryPointsTree deep y)+  GBuildEntryPointsTree 'False (G.C1 _ _) =+    'EPLeaf+  GBuildEntryPointsTree 'True (G.C1 _ x) =+    GBuildEntryPointsTree 'True x+  GBuildEntryPointsTree deep (G.S1 _ x) =+    GBuildEntryPointsTree deep x+  GBuildEntryPointsTree _ G.U1 =+    'EPLeaf+  GBuildEntryPointsTree _ (_ G.:*: _) =+    'EPLeaf+  GBuildEntryPointsTree deep (G.Rec0 a) =+    If (IsPrimitiveValue a)+       'EPLeaf+       (BuildEPTree deep a)++-- | Traverses sum type and constructs 'Notes' which report+-- constructor names via field annotations.+type EntryPointsNotes deep ep a = (Generic a, GEntryPointsNotes deep ep (G.Rep a))++-- | Makes up notes with proper field annotations for given parameter.+mkEntryPointsNotes+  :: forall deep ep a.+      (EntryPointsNotes deep ep a, IsGenericIsoValue a, HasCallStack)+  => Notes (ToT a)+mkEntryPointsNotes = fst $ gMkEntryPointsNotes @deep @ep @(G.Rep a)++-- | Generic traversal for 'EntryPointsNotes'.+class GEntryPointsNotes (deep :: Bool) (ep :: EPTree) (x :: Kind.Type -> Kind.Type) where+  {- | Returns:+    1. Notes corresponding to this level;+    2. Field annotation for this level (and which should be used one level above).+  -}+  gMkEntryPointsNotes :: HasCallStack => (Notes (GValueType x), FieldAnn)++instance GEntryPointsNotes deep ep x => GEntryPointsNotes deep ep (G.D1 i x) where+  gMkEntryPointsNotes = gMkEntryPointsNotes @deep @ep @x++instance+    ( GEntryPointsNotes deep epx x+    , GEntryPointsNotes deep epy y+    )+  =>+    GEntryPointsNotes deep ('EPNode epx epy) (x G.:+: y)+  where+  gMkEntryPointsNotes =+    let (xnotes, xann) = gMkEntryPointsNotes @deep @epx @x+        (ynotes, yann) = gMkEntryPointsNotes @deep @epy @y+    in (NTOr noAnn xann yann xnotes ynotes, noAnn)++instance (GHasTypeAnn x, KnownSymbol ctor) =>+         GEntryPointsNotes 'False ep (G.C1 ('G.MetaCons ctor _1 _2) x) where+  gMkEntryPointsNotes =+    (gGetTypeAnn @x, ctorNameToAnn (symbolValT' @ctor))++instance (GHasTypeAnn x, KnownSymbol ctor) =>+         GEntryPointsNotes 'True 'EPLeaf (G.C1 ('G.MetaCons ctor _1 _2) x) where+  gMkEntryPointsNotes =+    (gGetTypeAnn @x, ctorNameToAnn (symbolValT' @ctor))++instance (ep ~ 'EPNode epx epy, GEntryPointsNotes 'True ep x) =>+         GEntryPointsNotes 'True ('EPNode epx epy) (G.C1 ('G.MetaCons ctor _1 _2) x) where+  gMkEntryPointsNotes = gMkEntryPointsNotes @'True @ep @x++instance GEntryPointsNotes deep ep x => GEntryPointsNotes deep ep (G.S1 i x) where+  gMkEntryPointsNotes = gMkEntryPointsNotes @deep @ep @x++instance (EntryPointsNotes deep ep a, IsGenericIsoValue a) =>+         GEntryPointsNotes deep ep (G.Rec0 a) where+  gMkEntryPointsNotes = (mkEntryPointsNotes @deep @ep @a, noAnn)++instance GEntryPointsNotes deep 'EPLeaf G.U1 where+  gMkEntryPointsNotes = (starNotes, noAnn)++instance+    ( Typeable (GValueType x)+    , Typeable (GValueType y)+    , SingI (GValueType x)+    , SingI (GValueType y)+    )+  =>+    GEntryPointsNotes deep 'EPLeaf (x G.:*: y)+  where+  gMkEntryPointsNotes = (starNotes, noAnn)++-- For supporting type annotations of entrypoint arguments.+--+--At the botton of this infra is the HasTypeAnn class, which defines the type+--annotations for a given type. Right now the type annotations can only come+--from names in a named field. That is, we are not deriving names from, for+--example, record field names.++class HasTypeAnn a where+  getTypeAnn :: Notes (ToT a)++instance {-# OVERLAPPABLE #-} (GHasTypeAnn (G.Rep a), GValueType (G.Rep a) ~ ToT a)+  => HasTypeAnn a where+  getTypeAnn = gGetTypeAnn @(G.Rep a)++instance (HasTypeAnn a, KnownSymbol name)+  => HasTypeAnn (NamedF Identity a name) where+  getTypeAnn = insertNote (symbolAnn @name) $ getTypeAnn @a+    where+      symbolAnn :: forall s. KnownSymbol s => TypeAnn+      symbolAnn = ann $ symbolValT' @s+      -- Insert the provided type annotation into the provided note.+      insertNote :: forall (b :: T). TypeAnn -> Notes b -> Notes b+      insertNote nt s = case s of+        NTc _ -> NTc nt+        NTKey _ -> NTKey nt+        NTUnit _ -> NTUnit nt+        NTSignature _ -> NTSignature nt+        NTOption _ n1  -> NTOption nt n1+        NTList _ n1 -> NTList nt n1+        NTSet _ n1 -> NTSet nt n1+        NTOperation _ -> NTOperation nt+        NTContract _ n1 -> NTContract nt n1+        NTPair _ n1 n2 n3 n4 -> NTPair nt n1 n2 n3 n4+        NTOr _ n1 n2 n3 n4 -> NTOr nt n1 n2 n3 n4+        NTLambda _ n1 n2 -> NTLambda nt n1 n2+        NTMap _ n1 n2 -> NTMap nt n1 n2+        NTBigMap _ n1 n2 -> NTBigMap nt n1 n2+        NTChainId _ -> NTChainId nt++instance (HasTypeAnn (Maybe a), KnownSymbol name)+  => HasTypeAnn (NamedF Maybe a name) where+  getTypeAnn = getTypeAnn @(NamedF Identity (Maybe a) name)++-- Primitive instances+instance (HasTypeAnn a) => HasTypeAnn (Maybe a) where+  getTypeAnn = NTOption noAnn (getTypeAnn @a)++instance HasTypeAnn Integer where+  getTypeAnn = starNotes++instance HasTypeAnn Natural where+  getTypeAnn = starNotes++instance HasTypeAnn MText where+  getTypeAnn = starNotes++instance HasTypeAnn Bool where+  getTypeAnn = starNotes++instance HasTypeAnn ByteString where+  getTypeAnn = starNotes++instance HasTypeAnn Mutez where+  getTypeAnn = starNotes++instance HasTypeAnn Address where+  getTypeAnn = starNotes++instance HasTypeAnn EpAddress where+  getTypeAnn = starNotes++instance HasTypeAnn KeyHash where+  getTypeAnn = starNotes++instance HasTypeAnn Timestamp where+  getTypeAnn = starNotes++instance HasTypeAnn PublicKey where+  getTypeAnn = starNotes++instance HasTypeAnn Signature where+  getTypeAnn = starNotes++instance (HasTypeAnn a) => HasTypeAnn (ContractRef a) where+  getTypeAnn = NTContract noAnn (getTypeAnn @a)++instance (HasTypeAnn v) => HasTypeAnn (Map k v) where+  getTypeAnn = NTMap noAnn noAnn (getTypeAnn @v)++instance (HasTypeAnn v) => HasTypeAnn (BigMap k v) where+  getTypeAnn = NTBigMap noAnn noAnn (getTypeAnn @v)++instance (SingI (ToCT v), Typeable (ToCT v)) => HasTypeAnn (Set v) where+  getTypeAnn = starNotes++instance (HasTypeAnn a) => HasTypeAnn [a] where+  getTypeAnn = NTList noAnn (getTypeAnn @a)++instance HasTypeAnn Operation where+  getTypeAnn = starNotes++instance+    ( HasTypeAnn (ZippedStack i)+    , HasTypeAnn (ZippedStack o)+    )+  =>+    HasTypeAnn (i :-> o)+  where+  getTypeAnn = NTLambda noAnn+    (getTypeAnn @(ZippedStack i))+    (getTypeAnn @(ZippedStack o))++-- A Generic HasTypeAnn implementation+class GHasTypeAnn a where+  gGetTypeAnn :: Notes (GValueType a)++instance GHasTypeAnn G.U1 where+  gGetTypeAnn = starNotes++instance (GHasTypeAnn x) => GHasTypeAnn (G.M1 i0 i1 x) where+  gGetTypeAnn = gGetTypeAnn @x++instance+    ( GHasTypeAnn x+    , GHasTypeAnn y+    )+  =>+    GHasTypeAnn (x G.:+: y)+  where+  gGetTypeAnn = NTOr noAnn noAnn noAnn+    (gGetTypeAnn @x)+    (gGetTypeAnn @y)++instance+    ( GHasTypeAnn x+    , GHasTypeAnn y+    )+  =>+    GHasTypeAnn (x G.:*: y)+  where+  gGetTypeAnn = NTPair noAnn noAnn noAnn+    (gGetTypeAnn @x)+    (gGetTypeAnn @y)++instance (HasTypeAnn x) => GHasTypeAnn (G.Rec0 x) where+  gGetTypeAnn = getTypeAnn @x
+ src/Lorentz/EntryPoints/Doc.hs view
@@ -0,0 +1,209 @@+-- | Utilities for declaring and documenting entry points.+module Lorentz.EntryPoints.Doc+  ( DEntryPoint (..)+  , PlainEntryPointsKind+  , diEntryPointToMarkdown+  , DEntryPointArg (..)+  , DeriveCtorFieldDoc (..)+  , ParamBuildingStep (..)+  , clarifyParamBuildingSteps+  , mkDEntryPointArgSimple+  , entryCase+  ) where++import qualified Data.Kind as Kind+import Data.Vinyl.Core (Rec(..), rappend)+import Fmt (build)+import GHC.Generics ((:+:))+import qualified GHC.Generics as G+import GHC.TypeLits (KnownSymbol, symbolVal)++import Lorentz.ADT+import Lorentz.Base+import Lorentz.Doc+import Michelson.Typed.Doc+import Michelson.Typed.Haskell.Doc+import Michelson.Typed.Haskell.Instr+import Util.Markdown+import Util.Type+import Util.TypeTuple++-- | Gathers information about single entry point.+--+-- We assume that entry points might be of different kinds,+-- which is designated by phantom type parameter.+-- For instance, you may want to have several groups of entry points+-- corresponding to various parts of a contract - specifying different @kind@+-- type argument for each of those groups will allow you defining different+-- 'DocItem' instances with appropriate custom descriptions for them.+data DEntryPoint (kind :: Kind.Type) = DEntryPoint Text SubDoc++-- | Default implementation of 'docItemToMarkdown' for entry points.+diEntryPointToMarkdown :: HeaderLevel -> DEntryPoint level -> Markdown+diEntryPointToMarkdown lvl (DEntryPoint name block) =+  mdSeparator <>+  mdHeader lvl (mdTicked $ build name) <>+  subDocToMarkdown (nextHeaderLevel lvl) block++-- | Default value for 'DEntryPoint' type argument.+data PlainEntryPointsKind++instance DocItem (DEntryPoint PlainEntryPointsKind) where+  type DocItemPosition (DEntryPoint PlainEntryPointsKind) = 1000+  docItemSectionName = Just "Entry points"+  docItemToMarkdown = diEntryPointToMarkdown++-- | During incremental assembly of parameter building steps -+-- current representation of parameter.+type CurrentParam = Markdown++-- | Describes a parameter building step.+--+-- This can be wrapping into (Haskell) constructor, or a more complex+-- transformation.+data ParamBuildingStep = ParamBuildingStep+  { pbsEnglish :: Markdown+    -- ^ Plain english description of this step.+  , pbsHaskell :: CurrentParam -> Markdown+    -- ^ How to construct parameter in Haskell code.+  , pbsMichelson :: CurrentParam -> Markdown+    -- ^ How to construct parameter working on raw Michelson.+  }++-- | Describes argument of an entry point.+data DEntryPointArg = DEntryPointArg+  { epaArg :: Maybe DType+    -- ^ Argument of the entry point. Pass 'Nothing' if no argument is required.+  , epaBuilding :: [ParamBuildingStep]+    -- ^ Describes a way to lift an entry point argument into full parameter+    -- which can be passed to the contract.+    --+    -- Steps are supposed to be applied in the order in which they are given.+    -- E.g. suppose that an entry point is called as @Run (Service1 arg)@;+    -- then the first step should describe wrapping into @Service1@ constructor,+    -- and the second step should be about wrapping into @Run@ constructor.+  }++mkDEntryPointArgSimple :: forall t. TypeHasDoc t => DEntryPointArg+mkDEntryPointArgSimple = DEntryPointArg+  { epaArg = Just $ DType (Proxy @t)+  , epaBuilding = []+  }++-- | Go over contract code and update every occurrence of 'DEntryPointArg'+-- documentation item, adding the given step to its "how to build parameter"+-- description.+clarifyParamBuildingSteps :: ParamBuildingStep -> (inp :-> out) -> (inp :-> out)+clarifyParamBuildingSteps pbs =+  iMapAnyCode $+  modifyInstrDoc (\di -> di{ epaBuilding = epaBuilding di ++ [pbs] })++instance DocItem DEntryPointArg where+  type DocItemPosition DEntryPointArg = 20+  docItemSectionName = Nothing+  docItemDependencies (DEntryPointArg mdty _) =+    [SomeDocDefinitionItem dty | Just dty <- pure mdty]+  docItemToMarkdown _ (DEntryPointArg mdty psteps) =+    mconcat . Prelude.map (<> "\n\n") $+      [ mdSubsection "Parameter" $+          case mdty of+            Nothing -> "none (pass unit)"+            Just (DType dty) -> typeDocMdReference dty (WithinParens False)++      , mdSpoiler "How to call this entry point" . mconcat $+          [ "\n0. Construct parameter for the entry point.\n"+          , mconcat . Prelude.intersperse "\n" $+              psteps <&> \ParamBuildingStep{..} ->+                mconcat . Prelude.intersperse "\n" $+                [ -- Markdown re-enumerates enumerated lists automatically+                  "1. " <> pbsEnglish+                , "    + " <>+                  mdSubsection "In Haskell" (mdTicked $ pbsHaskell "·")+                , "    + " <>+                  mdSubsection "In Michelson" (mdTicked $ pbsMichelson "·")+                ]+          , "\n\nPass resulting value as parameter to the contract.\n"+          ]+      ]++-- | Pick a type documentation from 'CtorField'.+class DeriveCtorFieldDoc (cf :: CtorField) where+  deriveCtorFieldDoc :: Maybe DType+instance DeriveCtorFieldDoc 'NoFields where+  deriveCtorFieldDoc = Nothing+instance TypeHasDoc ty => DeriveCtorFieldDoc ('OneField ty) where+  deriveCtorFieldDoc = Just $ DType (Proxy @ty)++-- | Add necessary documentation to entry points.+documentEntryPoints+  :: forall a kind inp out.+     DocumentEntryPoints kind a+  => Rec (CaseClauseL inp out) (CaseClauses a)+  -> Rec (CaseClauseL inp out) (CaseClauses a)+documentEntryPoints = gDocumentEntryPoints @kind @(G.Rep a) id++-- | Constraint for 'documentEntryPoints'.+type DocumentEntryPoints kind a =+  (Generic a, GDocumentEntryPoints kind (G.Rep a))++-- | Traverse entry points and add parameter building step (which describes+-- necessity to wrap parameter into some constructor of the given datatype)+-- to all parameters described within given code.+class GDocumentEntryPoints (kind :: Kind.Type) (x :: Kind.Type -> Kind.Type) where+  -- | Add corresponding parameter building step.+  --+  -- First argument is accumulator for Michelson description of the building step.+  gDocumentEntryPoints+    :: (Markdown -> Markdown)+    -> Rec (CaseClauseL inp out) (GCaseClauses x)+    -> Rec (CaseClauseL inp out) (GCaseClauses x)++instance GDocumentEntryPoints kind x => GDocumentEntryPoints kind (G.D1 i x) where+  gDocumentEntryPoints = gDocumentEntryPoints @kind @x++instance ( GDocumentEntryPoints kind x, GDocumentEntryPoints kind y+         , RSplit (GCaseClauses x) (GCaseClauses y)+         ) =>+         GDocumentEntryPoints kind (x :+: y) where+  gDocumentEntryPoints michDesc clauses =+    let (lclauses, rclauses) = rsplit @CaseClauseParam @(GCaseClauses x) clauses+    in gDocumentEntryPoints @kind @x+         (\a -> michDesc $ "Left (" <> a <> ")")+         lclauses+       `rappend`+       gDocumentEntryPoints @kind @y+         (\a -> michDesc $ "Right (" <> a <> ")")+         rclauses++instance ( 'CaseClauseParam ctor cf ~ GCaseBranchInput ctor x+         , KnownSymbol ctor+         , DocItem (DEntryPoint kind)+         , DeriveCtorFieldDoc cf+         ) =>+         GDocumentEntryPoints kind (G.C1 ('G.MetaCons ctor _1 _2) x) where+  gDocumentEntryPoints michDesc (CaseClauseL clause :& RNil) =+    let entryPointName = toText $ symbolVal (Proxy @ctor)+        psteps = ParamBuildingStep+          { pbsEnglish = "Wrap into " <> mdTicked (build entryPointName) <> " constructor."+          , pbsHaskell = \p -> build entryPointName <> " (" <> p <> ")"+          , pbsMichelson = michDesc+          }+        addDoc instr =+          clarifyParamBuildingSteps psteps $+          docGroup (SomeDocItem . DEntryPoint @kind entryPointName) $+          doc (DEntryPointArg (deriveCtorFieldDoc @cf) []) # instr+    in CaseClauseL (addDoc clause) :& RNil++-- | Like 'caseT', to be used for pattern-matching on parameter.+--+-- Modifies documentation accordingly. Including description of+-- entrypoints' arguments, thus for them you will need to supply+-- 'TypeHasDoc' instance.+entryCase+  :: forall dt entryPointKind out inp clauses.+     ( CaseTC dt out inp clauses+     , DocumentEntryPoints entryPointKind dt+     )+  => Proxy entryPointKind -> IsoRecTuple clauses -> dt & inp :-> out+entryCase _ =+  case_ . documentEntryPoints @dt @entryPointKind . recFromTuple
src/Lorentz/Errors.hs view
@@ -1,62 +1,678 @@-{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DerivingStrategies, DeriveAnyClass #-}+{-# LANGUAGE TypeFamilyDependencies #-} --- | Advanced errors.+-- We want to make sure 'failUsingArg' is used with sane argument.+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+ module Lorentz.Errors-  ( IsError-  , LorentzUserError-  , unLorentzUserError-  , UserFailInstr-  , userFailWith+  ( -- * Haskell to 'Value' conversion+    IsError (..)+  , isoErrorToVal+  , isoErrorFromVal+  , ErrorHasDoc (..)+  , typeDocMdDescriptionReferToError++  , UnspecifiedError (..)++    -- * General instructions+  , failUsing+  , failUnexpected++    -- * Custom errors+  , ErrorArg+  , CustomError (..)+  , failCustom+  , failCustom_++    -- * Documentation+  , ErrorClass (..)+  , CustomErrorHasDoc (..)+  , DError (..)+  , DThrows (..)++    -- * Old interface (DEPRECATED)+  , customErrorToVal+  , customErrorFromVal+  , failUsingArg+  , FailUsingArg+  , CustomErrorNoIsoValue+  , deriveCustomError++  , errorsDocumentation   ) where -import Data.Singletons (SingI)+import Data.Singletons (SingI(..), demote)+import qualified Data.Char as C+import qualified Data.List as L+import Data.Typeable (cast)+import qualified Text.Show+import qualified Language.Haskell.TH as TH import Data.Vinyl.Derived (Label)-import GHC.TypeLits (KnownSymbol, symbolVal)+import Data.Constraint (Dict (..))+import Fmt ((+|), (+||), (|+), (||+), pretty, fmt, build, Buildable)+import qualified Data.Kind as Kind+import Data.Type.Equality (type (==))+import GHC.TypeLits (ErrorMessage(..), KnownSymbol, TypeError, symbolVal, Symbol) -import Lorentz.ADT import Lorentz.Base-import Lorentz.Coercions-import Lorentz.Constraints-import Lorentz.Instr+import Lorentz.Doc+import Lorentz.Instr hiding (cast) import Lorentz.Value import Michelson.Text import Michelson.Typed.Haskell+import Michelson.Typed.Instr+import Michelson.Typed.Scope+import Michelson.Typed.Sing+import Michelson.Typed.T+import Michelson.Typed.Value+import Util.Typeable+import Util.TypeLits+import Util.Type+import Util.Markdown --- | Constraints on an object you can fail with.-type IsError err =-  ( IsoValue err-  , KnownValue err-  , NoOperation err-  , NoBigMap err+----------------------------------------------------------------------------+-- IsError+----------------------------------------------------------------------------++type ErrorScope t =+  -- We can require a weaker constraint (e.g. no 'HasNoOp'), but+  -- for now it's the simplest way to make 'failUsing' work+  ( Typeable t+  , ConstantScope t   ) --- | A unique error identifier.-newtype ErrorTag = ErrorTag MText-  deriving newtype (Show, Eq, Ord, IsString, IsoValue)+type KnownError a = ErrorScope (ToT a) --- | An error indicating a normal failure caused by such user input.-type LorentzUserError e = (ErrorTag, e)+-- | Haskell type representing error.+class (Typeable e, ErrorHasDoc e) => IsError e where --- | Pseudo-getter for error within 'LorentzUserError'.-unLorentzUserError :: LorentzUserError e -> e-unLorentzUserError = snd+  -- | Converts a Haskell error into @Value@ representation.+  errorToVal :: e -> (forall t. ErrorScope t => Value t -> r) -> r +  -- | Converts a @Value@ into Haskell error.+  errorFromVal :: (Typeable t, SingI t) => Value t -> Either Text e++-- | Implementation of 'errorToVal' via 'IsoValue'.+isoErrorToVal+  :: (KnownError e, IsoValue e)+  => e -> (forall t. ErrorScope t => Value t -> r) -> r+isoErrorToVal e cont = cont $ toVal e++-- | Implementation of 'errorFromVal' via 'IsoValue'.+isoErrorFromVal+  :: (Typeable t, Typeable (ToT e), IsoValue e)+  => Value t -> Either Text e+isoErrorFromVal e = fromVal <$> gcastE e++class ErrorHasDoc e where+  -- | Name of error as it appears in the corresponding section title.+  errorDocName :: Text++  -- | What should happen for this error to be raised.+  errorDocMdCause :: Markdown++  -- | Brief version of 'errorDocMdCause'.+  --+  -- This will appear along with the error when mentioned in entrypoint description.+  -- By default, the first sentence of the full description is used.+  errorDocMdCauseInEntrypoint :: Markdown+  errorDocMdCauseInEntrypoint = pickFirstSentence $ errorDocMdCause @e++  -- | How this error is represented in Haskell.+  errorDocHaskellRep :: Markdown++  -- | Error class.+  errorDocClass :: ErrorClass+  errorDocClass = ErrClassUnknown++  -- | Which definitions documentation for this error mentions.+  errorDocDependencies :: [SomeDocDefinitionItem]++-- | Helper for managing descriptions.+pickFirstSentence :: Markdown -> Markdown+pickFirstSentence = build . toText . go . fmt+  where+    go :: String -> String+    go = \case+      '.' : c : _ | C.isSpace c -> "."+      c : s -> c : go s+      "" -> ""++-- Instances+----------------------------------------------------------------------------++-- | Use this for internal errors only.+--+-- "Normal" error scenarios should use the mechanism of custom errors, see below.+instance IsError MText where+  errorToVal = isoErrorToVal+  errorFromVal = isoErrorFromVal++instance ErrorHasDoc MText where+  errorDocName = "InternalError"+  errorDocMdCause =+    "Internal error occured."+  errorDocHaskellRep =+    "Textual error message, see " <>+    typeDocMdReference (Proxy @MText) (WithinParens False) <> "."+  errorDocClass = ErrClassContractInternal+  errorDocDependencies = [SomeDocDefinitionItem (DType $ Proxy @MText)]++instance TypeError ('Text "Use representative error messages") => IsError () where+  errorToVal _ _ = error "impossible"+  errorFromVal = error "impossible"++instance TypeError ('Text "Use representative error messages") => ErrorHasDoc () where+  errorDocName = error "impossible"+  errorDocMdCause = error "impossible"+  errorDocHaskellRep = error "impossible"+  errorDocDependencies = error "impossible"++-- | Use this type as replacement for @()@ when you __really__ want to leave+-- error cause unspecified.+data UnspecifiedError = UnspecifiedError+  deriving stock Generic+  deriving anyclass IsoValue++instance IsError UnspecifiedError where+  errorToVal = isoErrorToVal+  errorFromVal = isoErrorFromVal++instance ErrorHasDoc UnspecifiedError where+  errorDocName = "Unspecified error"+  errorDocMdCause = "Some error occured."+  errorDocHaskellRep = typeDocMdReference (Proxy @()) (WithinParens False) <> "."+  errorDocDependencies = typeDocDependencies' (Proxy @())++----------------------------------------------------------------------------+-- General instructions+----------------------------------------------------------------------------++-- | Fail with the given Haskell value.+failUsing+  :: forall e s t.+     (IsError e)+  => e -> s :-> t+failUsing err =+  errorToVal err $ \eval ->+    doc (DThrows (Proxy @e)) #+    (FI $ PUSH eval `Seq` FAILWITH)++-- | Fail, providing a reference to the place in the code where+-- this function is called.+--+-- Like 'error' in Haskell code, this instruction is for internal errors only.+failUnexpected :: MText -> s :-> t+failUnexpected msg = failUsing $ [mt|Internal: |] <> msg++----------------------------------------------------------------------------+-- Custom errors+----------------------------------------------------------------------------++{- | Declares a custom error, defining @error name - error argument@ relation.++If your error is supposed to carry no argument, then provide @()@.++Note that this relation is defined globally rather than on per-contract basis,+so define errors accordingly. If your error has argument specific to your+contract, call it such that error name reflects its belonging to this contract.+-}++{- About global registry of errors:++Pros: this allows defining pieces of code which can be reused among the contracts.++Cons: possible name collisions. Example of worst case: two libraries define+different errors for the same tag, attempt to use both of these libraries would+cause compile-time error. But such infrastructure will barely take place in+practice.+-}+{- For future work:++* Assosiating unique numeric error codes to tags, and put codes into+the contract instead of tags. This allows getting rid of overhead related to+often long tag literals.++* Allow using arbitrary type instead of tag (and 'KnownSymbol' constraint will+be replaced with a more generic one).+Some users may prefer using datatypes as tags rather than type-level strings as tags+because+  * there will be no orphan instances then+  * no problem with name collisions+  * compiler will prompt a hint in case of typo in tag name+  * in some cases autocomplete handles declarations in code better than strings+(and cons here is that each such tag will need to be declared first).++-}+type family ErrorArg (tag :: Symbol) :: Kind.Type++-- | Material custom error.+--+-- Use this in pattern matches against error (e.g. in tests).+data CustomError (tag :: Symbol) = CustomError+  { ceTag :: Label tag+  , ceArg :: ErrorArg tag+  }++deriving stock instance Eq (ErrorArg tag) => Eq (CustomError tag)+deriving stock instance Show (ErrorArg tag) => Show (CustomError tag)++-- | How 'CustomError' is actually represented in Michelson.+type CustomErrorRep tag = (MText, ErrorArg tag)++-- | This instance cannot be implemented, use 'IsError' instance instead.+instance TypeError ('Text "CustomError has no IsoValue instance") =>+         IsoValue (CustomError tag) where+  type ToT (CustomError tag) = TypeError ('Text "CustomError has no IsoValue instance")+  toVal = error "impossible"+  fromVal = error "impossible"++instance (CustomErrorHasDoc tag, KnownError (ErrorArg tag), IsoValue (ErrorArg tag)) =>+         IsError (CustomError tag) where+  errorToVal (CustomError l arg) cont =+    cont $ toVal @(CustomErrorRep tag) (errorTagToMText l, arg)+  errorFromVal (v :: Value t) =+    let expectedTag = errorTagToMText (fromLabel @tag)+    in case cast v of+        Just v' ->+          let (tag, arg) = fromVal @(CustomErrorRep tag) v'+          in if tag == expectedTag+             then Right $ CustomError fromLabel arg+             else Left $ "Bad tag, expected " +| expectedTag |+ ", got " +| tag |+ ""+        Nothing -> Left $ "Wrong type for custom error: " <> pretty (demote @t)++instance (CustomErrorHasDoc tag, SingI (ToT (ErrorArg tag))) =>+         ErrorHasDoc (CustomError tag) where+  errorDocName = errorTagToText @tag+  errorDocDependencies = typeDocDependencies' (Proxy @(ErrorArg tag))+  errorDocMdCause = customErrDocMdCause @tag+  errorDocMdCauseInEntrypoint = customErrDocMdCauseInEntrypoint @tag+  errorDocClass = customErrClass @tag+  errorDocHaskellRep =+    let hasArg = demote @(ToT (ErrorArg tag)) /= TUnit+        name = build $ errorTagToText @tag+    in mconcat $ catMaybes+      [ Just $+          ( if hasArg+            then mdTicked ("(\"" <> name <> "\", " <> "<error argument>" <> ")")+            else mdTicked ("(\"" <> name <> "\", ())")+          ) <> "."+      , guard hasArg $>+          ("\n\nProvided error argument will be of type "+          <> typeDocMdReference (Proxy @(ErrorArg tag)) (WithinParens False)+          <> (maybe "" (\txt -> " and stand for " <> txt) (customErrArgumentSemantics @tag))+          <> "."+          )+      ]++-- | Demote error tag to term level.+errorTagToMText :: KnownSymbol tag => Label tag -> MText+errorTagToMText l =+  -- Now tags come not from constructor names, but from labels,+  -- we have to lead the first letter to upper case to preserve+  -- compatibility with FA1.2 interface.+  mtextHeadToUpper $+    labelToMText l++errorTagToText :: forall tag. KnownSymbol tag => Text+errorTagToText = toText $ errorTagToMText (fromLabel @tag)++-- | Fail with given custom error.+failCustom+  :: forall tag err s any.+     ( err ~ ErrorArg tag+     , CustomErrorHasDoc tag+     , KnownError err+     )+  => Label tag -> err : s :-> any+failCustom l =+  doc (DThrows (Proxy @(CustomError tag))) #+  push (errorTagToMText l) # pair @MText @err #+  FI (FAILWITH @(ToT (CustomErrorRep tag)))++-- | Specialization of 'failCustom' for no-arg errors.+failCustom_+  :: forall tag s any notVoidError.+     ( TypeErrorUnless (ErrorArg tag == ()) notVoidError+     , CustomErrorHasDoc tag+     , notVoidError ~+         ('Text "Expected no-arg error, but given error requires argument of type "+          ':<>: 'ShowType (ErrorArg tag)+         )+     )+  => Label tag -> s :-> any+failCustom_ l =+  inTypeErrorUnless @(ErrorArg tag == ()) @notVoidError $+  reifyTypeEquality @(ErrorArg tag) @() $+    unit # failCustom l++-- Special treatment of no-arg errors+----------------------------------------------------------------------------++instance Eq (ErrorArg tag) => Eq (() -> CustomError tag) where+  e1 == e2 = e1 () == e2 ()+instance Show (ErrorArg tag) => Show (() -> CustomError tag) where+  show e = show (e ())++-- | If 'CustomError' constructor is not provided its argument, we assume+-- that this is no-arg error and interpret the passed value as complete.+instance ( Typeable arg+         , IsError (CustomError tag)+         , TypeErrorUnless (arg == ()) notVoidError+         , arg ~ ErrorArg tag+         , notVoidError ~+            ('Text "This error requires argument of type "+              ':<>: 'ShowType (ErrorArg tag)+            )+         ) =>+         IsError (arg -> CustomError tag) where+  errorToVal mkCustomError cont =+    inTypeErrorUnless @(arg == ()) @notVoidError $+    reifyTypeEquality @arg @() $+      errorToVal (mkCustomError ()) cont+  errorFromVal v =+    inTypeErrorUnless @(arg == ()) @notVoidError $+    reifyTypeEquality @arg @() $+      errorFromVal v <&> \(CustomError l ()) -> CustomError l++instance ErrorHasDoc (CustomError tag) => ErrorHasDoc (arg -> CustomError tag) where+  errorDocName = errorDocName @(CustomError tag)+  errorDocMdCauseInEntrypoint = errorDocMdCauseInEntrypoint @(CustomError tag)+  errorDocMdCause = errorDocMdCause @(CustomError tag)+  errorDocHaskellRep = errorDocHaskellRep @(CustomError tag)+  errorDocDependencies = errorDocDependencies @(CustomError tag)++----------------------------------------------------------------------------+-- Errors documentation injection into contracts+----------------------------------------------------------------------------++-- | Error class on how the error should be handled by the client.+data ErrorClass+  = ErrClassActionException+    -- ^ Normal expected error.+    -- Examples: "insufficient balance", "wallet does not exist".+  | ErrClassBadArgument+    -- ^ Invalid argument passed to entrypoint.+    -- Examples: your entrypoint accepts an enum represented as @nat@, and+    -- unknown value is provided.+    -- This includes more complex cases which involve multiple entrypoints.+    -- E.g. API provides iterator interface, middleware should care about using it+    -- hiding complex details and exposing a simpler API to user; then an attempt to+    -- request non-existing element would also correspond to an error from this class.+  | ErrClassContractInternal+    -- ^ Unexpected error. Most likely it means that there is a bug in+    -- the contract or the contract has been deployed incorrectly.+  | ErrClassUnknown+    -- ^ It's possible to leave error class unspecified.++instance Buildable ErrorClass where+  build = \case+    ErrClassActionException -> "Action exception"+    ErrClassBadArgument -> "Bad argument"+    ErrClassContractInternal -> "Internal"+    ErrClassUnknown -> "-"++isInternalErrorClass :: ErrorClass -> Bool+isInternalErrorClass = \case+  ErrClassActionException -> False+  ErrClassBadArgument -> False+  ErrClassContractInternal -> True+  ErrClassUnknown -> False++class (KnownSymbol tag, TypeHasDoc (ErrorArg tag), IsError (CustomError tag)) =>+      CustomErrorHasDoc tag where+  -- | What should happen for this error to be raised.+  customErrDocMdCause :: Markdown++  -- | Brief version of 'customErrDocMdCause'.+  -- This will appear along with the error when mentioned in entrypoint description.+  --+  -- By default, the first sentence of the full description is used.+  customErrDocMdCauseInEntrypoint :: Markdown+  customErrDocMdCauseInEntrypoint = pickFirstSentence $ customErrDocMdCause @tag++  -- | Error class.+  --+  -- By default this returns "unknown error" class; though you should provide+  -- explicit implementation in order to avoid a warning.+  customErrClass :: ErrorClass+  customErrClass = ErrClassUnknown++  -- | Clarification of error argument meaning.+  --+  -- Provide when it's not obvious, e.g. argument is not named with ':!'.+  --+  -- NOTE: This should /not/ be an entire sentence, rather just the semantic+  -- backbone.+  --+  -- Bad:+  -- * @Error argument stands for the previous value of approval.@+  --+  -- Good:+  -- * @the previous value of approval@+  -- * @pair, first argument of which is one thing, and the second is another@+  customErrArgumentSemantics :: Maybe Markdown+  customErrArgumentSemantics = Nothing+  {-# MINIMAL customErrDocMdCause, customErrClass #-}++-- | Mentions that contract uses given error.+data DError where+  DError :: IsError e => Proxy e -> DError++instance Eq DError where+  DError e1 == DError e2 = e1 `eqParam1` e2+instance Ord DError where+  DError e1 `compare` DError e2 = e1 `compareExt` e2++instance DocItem DError where+  type DocItemPosition DError = 5010+  type DocItemPlacement DError = 'DocItemInDefinitions+  docItemSectionName = Just "Errors"+  docItemSectionDescription = Just errorsDocumentation+  docItemRef (DError (_ :: Proxy e)) = DocItemRef $+    DocItemId ("errors-" <> errorDocName @e)+  docItemToMarkdown lvl (DError (_ :: Proxy e)) =+    mconcat+    [ mdSeparator+    , mdHeader lvl (mdTicked . build $ errorDocName @e)+    , mdSubsection "Class" (build $ errorDocClass @e)+    , "\n\n"+    , mdSubsection "Fires if" $ errorDocMdCause @e+    , "\n\n"+    , mdSubsection "Representation" $ errorDocHaskellRep @e+    ]+  docItemDependencies (DError (_ :: Proxy e)) = errorDocDependencies @e++errorDocMdReference :: forall e. IsError e => Markdown+errorDocMdReference =+  let DocItemRef (DocItemId anchor) = docItemRef $ DError (Proxy @e)+  in mdLocalRef (mdTicked . build $ errorDocName @e) anchor++-- | Documentation for custom errors.++-- | Mentions that entrypoint throws given error.+data DThrows where+  DThrows :: IsError e => Proxy e -> DThrows++instance Eq DThrows where+  DThrows e1 == DThrows e2 = eqParam1 e1 e2++instance DocItem DThrows where+  type DocItemPosition DThrows = 5011+  docItemSectionName = Just "Possible errors"+  docItemSectionNameStyle = DocSectionNameSmall+  docItemDependencies (DThrows ds) =+    [SomeDocDefinitionItem (DError ds)]+  docItemToMarkdown _ (DThrows (_ :: Proxy e)) =+    "* " <> errorDocMdReference @e <> " — " <> errorDocMdCauseInEntrypoint @e+  docItemsOrder =+    let errType (DThrows (_ :: Proxy e)) = errorDocClass @e+    in L.nub . filter (Prelude.not . isInternalErrorClass . errType)++-- | Implementation of 'typeDocMdDescription' (of 'TypeHasDoc' typeclass)+-- for Haskell types which sole purpose is to be error.+typeDocMdDescriptionReferToError :: forall e. IsError e => Markdown+typeDocMdDescriptionReferToError =+  "This type is primarily used as error, see " <>+  docDefinitionRef "description in section with errors" (DError (Proxy @e))++-- | This is to be included on top of @Errors@ section of the generated+-- documentation.+errorsDocumentation :: Markdown+errorsDocumentation = [md|+  Our contract implies the possibility of error scenarios, this section enlists+  all values which the contract can produce via calling `FAILWITH` instruction+  on them. In case of error, no changes to contract state will be applied.++  Each entrypoint also contains a list of errors which can be raised during its+  execution; only for no-throw entrypoints this list will be omitted.+  Errors in these lists are placed in the order in which the corresponding+  properties are checked unless the opposite is specified. I.e., if for a+  given entrypoint call two different errors may take place, the one which+  appears in the list first will be thrown.++  Most of the errors are represented according to the same+  `(error name, error argument)` pattern. See the list of errors below+  for details.++  We distinquish several error classes:+  + #{mdBold $ build ErrClassActionException}: given action cannot be performed with+    regard to the current contract state.++    Examples: "insufficient balance", "wallet does not exist".++    If you are implementing a middleware, such errors should be propagated to+    the client.++  + #{mdBold $ build ErrClassBadArgument}: invalid argument supplied to the entrypoint.++    Examples: entrypoint accepts a natural number from `0-3` range, and you+    supply `5`.++    If you are implementing a middleware, you should care about not letting+    such errors happen.++  + #{mdBold $ build ErrClassContractInternal}: contract-internal error.++    In ideal case, such errors should not take place, but still, make sure+    that you are ready to handle them. They can signal either invalid contract+    deployment or a bug in contract implementation.++    If an internal error is thrown, please report it to the author of this contract.+  |]++----------------------------------------------------------------------------+-- Old interface (DEPRECATED)+----------------------------------------------------------------------------++{- This API implements an approach when errors are declared via datatype+with constructors corresponding to error scenarios.+-}++-- | Implementation of 'errorToVal' for custom errors.+customErrorToVal+  :: (LooseSumC e, HasCallStack)+  => e+  -> (forall t. ErrorScope t => Value t -> r)+  -> r+customErrorToVal e cont =+  case toTaggedVal e of+    (tag, SomeValue (datVal :: Value t)) ->+      -- Tags come from constructors names, so we can assume+      -- the event of weird chars occurrence to be quite improbable+      let tag' = mkMTextUnsafe tag+      in case (opAbsense (sing @t), bigMapAbsense (sing @t), contractTypeAbsense (sing @t)) of+        (Just Dict, Just Dict, Just Dict) -> cont $ VPair (VC (CvString tag'), datVal)++        -- We could check this at type-level, but this would require+        -- specializing 'Michelson.Typed.LooseSum' to errors.+        -- We can do so, or assume that no one will ever try to put 'Operation'+        -- to error datatypes:+        (Nothing, _, _) -> error "Operation in constructor data"+        (_, Nothing, _) -> error "BigMap in constructor data"+        (_, _, Nothing) -> error "Contract in constructor data"+{-# DEPRECATED customErrorToVal "Datatype error declarations has been deprecated" #-}++-- | Implementation of 'errorFromVal' for custom errors.+--+-- This function is deprecated.+customErrorFromVal+  :: forall t e.+      (SingI t, LooseSumC e)+  => Value t -> Either Text e+customErrorFromVal v = case (v, sing @t) of+  (VPair (VC (CvString tag), datVal), STPair _ _) ->+    case fromTaggedVal (toText tag, SomeValue datVal) of+      ComposeOk e ->+        Right e+      ComposeCtorNotFound ->+        Left $ "Unknown error constructor " +| tag |+ ""+      ComposeFieldTypeMismatch got expected ->+        Left $ "Error data type mismatch, expected " +|| expected ||++                                            ", got " +|| got ||+ ""+  _ -> Left $ "Expected a (tag, dat) pair representing error"+{-# DEPRECATED customErrorFromVal "Datatype error declarations has been deprecated" #-}++-- | Prompt an error message saying that 'IsoValue' is not applicable for this type.+type family CustomErrorNoIsoValue a where+  CustomErrorNoIsoValue a = TypeError+    ('Text "No IsoValue instance for " ':<>: 'ShowType a ':$$:+     'Text "It has custom error representation")++-- | Derive 'IsError' instance for given type.+--+-- This will also forbid deriving 'IsoValue' instance for that type to avoid+-- having multiple different Michelson representations.+deriveCustomError :: TH.Name -> TH.Q [TH.Dec]+deriveCustomError name =+  [d|+    instance IsError $ty where+      errorToVal = customErrorToVal+      errorFromVal = customErrorFromVal++    instance CustomErrorNoIsoValue $ty => IsoValue $ty where+      type ToT $ty = CustomErrorNoIsoValue $ty+      toVal = error "impossible"+      fromVal = error "impossible"++    instance ErrorHasDoc $ty where+      errorDocName = "Some error"+      errorDocMdCause = "An error occurred."+      errorDocHaskellRep = "-"+      errorDocClass = ErrClassUnknown+      errorDocDependencies = []+  |]+  where+    ty = pure (TH.ConT name)+{-# DEPRECATED deriveCustomError "Datatype error declarations has been deprecated" #-}+ -- | Signature of 'userFailWith'.-type UserFailInstr e name s s'-  = (InstrWrapC e name, KnownSymbol name)-  => Label name -> AppendCtorField (GetCtorField e name) s :-> s'+type FailUsingArg e name fieldTy s s'+  = ( KnownSymbol name, IsError e+    , IsoValue fieldTy+    , CtorHasOnlyField name e fieldTy, Each [Typeable, SingI] '[ToT fieldTy]+    , HasCallStack+    )+  => Label name -> fieldTy : s :-> s'  -- | Fail with given error, picking argument for error from the top--- of the stack if any required. Error will be wrapped into 'LorentzUserError'--- (i.e. an error tag will be attached to the error data).+-- of the stack. --+-- If your error constructor does not carry an argument, use 'failUsing'+-- function instead. -- Consider the following practice: once error datatype for your contract -- is defined, create a specialization of this function to the error type.-userFailWith-  :: forall err name s s'.-      (Typeable (ToT err), SingI (ToT err))-  => UserFailInstr err name s s'-userFailWith label =-  wrap_ @err @_ @s label # push (mkMTextUnsafe . toText $ symbolVal (Proxy @name)) # pair #-  coerce_ @_ @(LorentzUserError err) #+--+-- This function is deprecated.+failUsingArg+  :: forall err name fieldTy s s'.+     FailUsingArg err name fieldTy s s'+failUsingArg _ =+  push (mkMTextUnsafe ctor) #+  pair #   failWith+  where+    ctor = case symbolVal (Proxy @name) of+      'c' : other -> toText other+      other -> error $ "Bad label provided: " +| other |+ ""+{-# DEPRECATED failUsingArg "Datatype error declarations has been deprecated" #-}
+ src/Lorentz/Errors/Common.hs view
@@ -0,0 +1,28 @@+{-# OPTIONS_GHC -Wno-orphans #-}++-- | Some common errors.+--+-- Such registry makes sense, as soon as errors are declared globally.+module Lorentz.Errors.Common () where++import Fmt (Buildable(..))++import Lorentz.Errors++----------------------------------------------------------------------------+-- Authorization+----------------------------------------------------------------------------++-- | Contract initiator should be contract admin in order to perform this+-- operation.+type instance ErrorArg "senderIsNotAdmin" = ()++instance Buildable (CustomError "senderIsNotAdmin") where+  build (CustomError _ ()) =+    "This operation can be executed only by admin, but is invoked by \+    \someone else"++instance CustomErrorHasDoc "senderIsNotAdmin" where+  customErrClass = ErrClassActionException+  customErrDocMdCause =+    "Entrypoint executed not by its administrator."
+ src/Lorentz/Errors/Numeric.hs view
@@ -0,0 +1,139 @@+-- | By default we represent error tags using strings. This module+-- makes it possible to use numbers instead.+--+-- There are two possible ways to use it:+-- 1. If you have just one Lorentz instruction (potentially a big one),+-- just use 'useNumericErrors' function. It will change error representation+-- there and return a map that can be used to interpret new error codes.+-- 2. If your contract consists of multiple parts, start with gathering all+-- error tags ('gatherErrorTags'). Then build 'ErrorTagMap' using+-- 'addNewErrorTags'. Pass empty map if you are building from scratch+-- (you can use 'buildErrorTagMap' shortcut) or an existing+-- map if you have one (e. g. you are upgrading a contract).++module Lorentz.Errors.Numeric+  ( ErrorTagMap+  , gatherErrorTags+  , addNewErrorTags+  , buildErrorTagMap+  , applyErrorTagMap+  , useNumericErrors++  , errorFromValNumeric+  ) where++import Data.Bimap (Bimap)+import qualified Data.Bimap as Bimap+import Data.Default (def)+import qualified Data.HashSet as HS+import Data.Singletons (SingI, sing)+import Fmt (pretty)++import Lorentz.Base+import Lorentz.Errors+import Michelson.Analyzer+import Michelson.FailPattern+import Michelson.Text (MText)+import Michelson.Typed++-- | This is a bidirectional map with correspondence between numeric+-- and textual error tags.+type ErrorTagMap = Bimap Natural MText++-- | Find all textual error tags that are used in typical+-- @FAILWITH@ patterns within given instruction.+-- Map them to natural numbers.+gatherErrorTags :: inp :-> out -> HashSet MText+gatherErrorTags = HS.fromMap . void . arErrorTags . analyze . iAnyCode++-- | Add more error tags to an existing 'ErrorTagMap'. It is useful when+-- your contract consists of multiple parts (e. g. in case of contract+-- upgrade), you have existing map for some part and want to add tags+-- from another part to it.+-- You can pass empty map as existing one if you just want to build+-- 'ErrorTagMap' from a set of textual tags. See 'buildErrorTagMap'.+addNewErrorTags :: ErrorTagMap -> HashSet MText -> ErrorTagMap+addNewErrorTags existingMap newTags =+  foldl' (flip $ uncurry Bimap.tryInsert) existingMap newItems+  where+    firstUnusedNumeric+      | Bimap.null existingMap = 0+      | otherwise = fst (Bimap.findMax existingMap) + 1++    newItems :: [(Natural, MText)]+    newItems = zip [firstUnusedNumeric .. ] (toList newTags)++-- | Build 'ErrorTagMap' from a set of textual tags.+buildErrorTagMap :: HashSet MText -> ErrorTagMap+buildErrorTagMap = addNewErrorTags Bimap.empty++-- | For each typical 'FAILWITH' that uses a string to represent error+-- tag this function changes error tag to be a number using the+-- supplied conversion map.+-- It assumes that supplied map contains all such strings+-- (and will error out if it does not).+-- It will always be the case if you gather all error tags using+-- 'gatherErrorTags' and build 'ErrorTagMap' from them using 'addNewErrorTags'.+applyErrorTagMap :: HasCallStack => ErrorTagMap -> inp :-> out -> inp :-> out+applyErrorTagMap errorTagMap = iMapAnyCode (applyErrorTagMapT errorTagMap)++-- | This function implements the simplest scenario of using this+-- module's functionality:+-- 1. Gather all error tags from a single instruction.+-- 2. Turn them into error conversion map.+-- 3. Apply this conversion.+useNumericErrors ::+  HasCallStack => inp :-> out -> (inp :-> out, ErrorTagMap)+useNumericErrors instr = (applyErrorTagMap errorTagMap instr, errorTagMap)+  where+    errorTagMap = buildErrorTagMap $ gatherErrorTags instr++-- This function works with 'Michelson.Typed' representation, not with Lorentz.+applyErrorTagMapT ::+     HasCallStack+  => ErrorTagMap+  -> Instr inp out+  -> Instr inp out+applyErrorTagMapT errorTagMap instr =+  dfsModifyInstr dfsSettings step instr+  where+    dfsSettings :: DfsSettings ()+    dfsSettings = def+      { dsGoToValues = True+      }++    tagToNatValue :: HasCallStack => MText -> Value ('Tc 'CNat)+    tagToNatValue tag =+      case Bimap.lookupR tag errorTagMap of+        -- It will be applied to textual tags detected by 'modifyTypicalFailWith'.+        -- Here we assume that all of them are discovered by the analyzer.+        -- If this error ever happens, it means that someone used+        -- 'applyErrorTagMap' with incomplete 'ErrorTagMap' or there is an+        -- internal bug somewhere.+        Nothing -> error $ "Can't find a tag: " <> pretty tag+        Just n -> VC $ CvNat n++    step :: HasCallStack => Instr inp out -> Instr inp out+    step = modifyTypicalFailWith tagToNatValue++-- | If you apply numeric error representation in your contract, 'errorFromVal'+-- will stop working because it doesn't know about this+-- transformation.+-- This function takes this transformation into account.+-- If a number is used as a tag, but it is not found in the passed+-- map, we conservatively preserve that number (because this whole+-- approach is rather a heuristic).+errorFromValNumeric ::+  (Typeable t, SingI t, IsError e) => ErrorTagMap -> Value t -> Either Text e+errorFromValNumeric errorTagMap v =+  case v of+    VC (CvNat tag)+      | Just textualTag <- Bimap.lookup tag errorTagMap ->+        errorFromVal . VC . CvString $ textualTag+    VPair (VC (CvNat tag), something)+      | Just textualTag <- Bimap.lookup tag errorTagMap+      , _ :: Value pair <- v ->+        case sing @pair of+          STPair {} ->+            errorFromVal $ VPair (VC $ CvString textualTag, something)+    _ -> errorFromVal v
src/Lorentz/Ext.hs view
@@ -6,11 +6,12 @@   ) where  import Data.Singletons (SingI)+import GHC.TypeNats (Nat)  import Lorentz.Base import Michelson.Typed.Haskell import Michelson.Typed.Instr-import Util.Peano+import Util.Peano hiding (Nat)  stackRef   :: forall (gn :: Nat) st n.@@ -22,10 +23,11 @@ printComment = I . Ext . PRINT  testAssert-  :: Typeable (ToTs out)+  :: (Typeable (ToTs out), HasCallStack)   => Text -> PrintComment (ToTs inp) -> inp :-> Bool & out -> inp :-> inp-testAssert msg comment (I instr) =-  I . (Ext . TEST_ASSERT) $ TestAssert msg comment instr+testAssert msg comment = \case+  I instr -> I . Ext . TEST_ASSERT $ TestAssert msg comment instr+  FI _ -> error "test assert branch always fails"  stackType :: forall s. s :-> s stackType = I Nop
+ src/Lorentz/Extensible.hs view
@@ -0,0 +1,268 @@+{- | This module contains implementation of 'Extensible' values.++@Extensible@ values are an alternative representation of sum-types+for Michelson. Instead of representing them as nested options, we+treat them as (Natural, ByteString) pair, where the first element+of the pair represents the constructor index, while the second is+a packed argument.++With such a representation sum types can be easily upgraded: it is+possible to add new elements to the sum type, and the representation+would not change.++However, such representation essentially limits the applicability of+the values. This module does not provide Michelson-level function to+unwrap the value because it would require traversing all the possible+options in the contract code. While this is possible, it is very+inefficient. Up to this moment, we have not come up with a decent+reason to allow such behavior, so Extensible types are write-only+in Michelson code. They can be unwrapped off-chain with @fromExtVal@.++In order to preserve previous values during migrations, users should+ONLY APPEND items to the underlying sum type. Changing, reordering and+deleting items is not allowed and would lead to compatibility breakage.+Currently, this restriction in not enforced. Only no-argument and+one-argument constructors are supported.++GOOD:+  -- `Extensible GoodSumTypeV1` is backwards compatible+  -- with `Extensible GoodSumTypeV2`+  data GoodSumTypeV1 = A Natural | B+  data GoodSumTypeV2 = A Natural | B | C MText++BAD:+  -- `Extensible BadSumTypeV1` is NOT backwards compatible+  -- with `Extensible BadSumTypeV2`+  data BadSumTypeV1 = A | B+  data BadSumTypeV2 = A Natural | B | C MText+-}++{-# LANGUAGE DeriveAnyClass, DerivingStrategies, InstanceSigs #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++module Lorentz.Extensible+  ( Extensible (..)+  , ExtConversionError (..)+  , ExtVal+  , ExtensibleHasDoc (..)+  , toExtVal+  , fromExtVal+  , wrapExt+  , WrapExtC+  ) where++import Data.Char (isSpace)+import qualified Data.Kind as Kind+import qualified Data.Text as T+import Data.Typeable (Proxy(..))+import Data.Vinyl.Derived (Label)+import Data.Vinyl.TypeLevel (type (++))+import Fmt (Buildable(build), (+||), (|+), (||+))+import GHC.Generics ((:+:)(..))+import qualified GHC.Generics as G+import GHC.TypeLits (AppendSymbol, Nat, Symbol)+import GHC.TypeNats (type (+))++import Lorentz.Base+import Lorentz.Coercions+import Lorentz.Constraints+import Lorentz.Instr+import Lorentz.Pack+import Michelson.Typed+import Util.Markdown+import Util.Type+import Util.TypeLits++newtype Extensible x = Extensible (Natural, ByteString)+  deriving stock (Generic, Eq, Show)+  deriving anyclass (IsoValue)++type ExtVal x = (Generic x, GExtVal x (G.Rep x))+type GetCtors x = GGetCtors (G.Rep x)++-- | Converts a value from a Haskell representation to its+--   extensible Michelson representation (i.e. (Natural, Bytestring) pair).+toExtVal :: ExtVal a => a -> Extensible a+toExtVal = gToExtVal . G.from++-- | Converts a value from an extensible Michelson representation to its+--   Haskell sum-type representation. Fails if the Michelson representation+--   points to a nun-existent constructor, or if we failed to unpack+--   the argument.+fromExtVal :: ExtVal a => Extensible a -> Either ExtConversionError a+fromExtVal val = fmap G.to $ gFromExtVal val++-- | Helper typeclass which allows us to sanely handle cases of no-arg+-- constructor and constructor with one argument.+class WrapExt (cf :: CtorField) where+  -- | Pack argument on top of the stack, if any required.+  packForWrap :: AppendCtorField cf s :-> ByteString : s++instance (NicePackedValue param) =>+         WrapExt ('OneField param) where+  packForWrap = pack++instance WrapExt 'NoFields where+  packForWrap = unit # pack++-- | Wraps an argument on top of the stack into an Extensible representation+wrapExt+  :: forall t (n :: Nat) name field s.+     (WrapExtC t n name field s)+  => Label ("c" `AppendSymbol` name) -> AppendCtorField field s :-> Extensible t ': s+wrapExt _ = packForWrap @field # push (natVal (Proxy @n)) # pair # coerce_++type WrapExtC t n name field s =+  ( 'Ctor n name field ~ LookupCtor name (EnumerateCtors (GetCtors t))+  , WrapExt field+  , KnownNat n+  )++-- | Errors related to fromExtVal conversion+data ExtConversionError+  = ConstructorIndexNotFound Natural+  | ArgumentUnpackFailed+  deriving stock (Eq, Show)++instance Buildable ExtConversionError where+  build =+    \case+      ConstructorIndexNotFound idx ->+        "Could not convert Extensible value into its Haskell representation: \+        \constructor #" +|| idx ||+ " was not found in the sum type \+        \constructors list"+      ArgumentUnpackFailed ->+        "Could not convert Extensible value into its Haskell representation: \+        \failed to unpack constructor argument"++data Position = Position Nat+data Ctor = Ctor { _n :: Nat, _name :: Symbol, _param :: CtorField }+type CtorKind = (Symbol, CtorField)++-- | Finds the constructor's position and argument type by its name+type family LookupCtor (name :: Symbol) (entries :: [Ctor])+             :: Ctor where+  LookupCtor name ('Ctor pos name param ': _) = 'Ctor pos name param+  LookupCtor name (_ ': entries) =+    LookupCtor name entries+  LookupCtor name '[] =+    TypeError ('Text "Constructor " ':<>: 'ShowType name ':<>:+               'Text " is not in the sum type constructor list")++-- | Transform list of 'CtorKind's to list of 'Ctor's, assigning numbers+-- to elements starting from 0.+type EnumerateCtors ctors = EnumerateCtorsImpl ('Position 0) ctors++type family EnumerateCtorsImpl (pos :: Position) (ctors :: [CtorKind]) :: [Ctor] where+  EnumerateCtorsImpl _ '[] = '[]+  EnumerateCtorsImpl ('Position i) ('(name, param) ': cs) =+    'Ctor i name param ': EnumerateCtorsImpl ('Position (i + 1)) cs++-- | Having a sum-type, yields a type-level list of its constructors+type family GGetCtors (x :: Kind.Type -> Kind.Type) :: [CtorKind] where+  GGetCtors (G.D1 _ x) = GGetCtors x+  GGetCtors (G.C1 ('G.MetaCons name _1 _2) (G.S1 _3 (G.Rec0 param)))+    = '[ '(name, 'OneField param) ]+  GGetCtors (G.C1 ('G.MetaCons name _1 _2) G.U1)+    = '[ '(name, 'NoFields) ]+  GGetCtors (x :+: y) = GGetCtors x ++ GGetCtors y++-- | Generic implementation of toExtVal and fromExtVal+class GExtVal t (x :: Kind.Type -> Kind.Type) where+  gToExtVal :: x p -> Extensible t+  gFromExtVal :: Extensible t -> Either ExtConversionError (x p)++instance GExtVal t x => GExtVal t (G.D1 i x) where+  gToExtVal = gToExtVal @t . G.unM1+  gFromExtVal val = fmap G.M1 (gFromExtVal @t val)++instance ( 'Ctor n name 'NoFields ~ LookupCtor name (EnumerateCtors (GetCtors t))+         , KnownNat n+         )+         => GExtVal t (G.C1 ('G.MetaCons name _1 _2) G.U1) where+  gToExtVal (G.M1 G.U1) = Extensible+    ( natVal (Proxy @n)+    , lPackValue ()+    )+  gFromExtVal (Extensible (idx, _))+    | idx == natVal (Proxy @n)+        = Right $ G.M1 G.U1+    | otherwise = Left $ ConstructorIndexNotFound idx++instance ( NiceFullPackedValue param+         , 'Ctor n name ('OneField param) ~ LookupCtor name (EnumerateCtors (GetCtors t))+         , KnownNat n+         )+         => GExtVal t (G.C1 ('G.MetaCons name _1 _2) (G.S1 _3 (G.Rec0 param))) where+  gToExtVal (G.M1 (G.M1 (G.K1 param))) = Extensible+    ( natVal (Proxy @n)+    , lPackValue param+    )+  gFromExtVal (Extensible (idx, bs))+    | idx == natVal (Proxy @n)+        = first (\_ -> ArgumentUnpackFailed) $+          fmap (G.M1 . G.M1 . G.K1) $ lUnpackValue @param bs+    | otherwise = Left $ ConstructorIndexNotFound idx++instance (GExtVal t x, GExtVal t y) => GExtVal t (x :+: y) where+  gToExtVal = \case+    G.L1 x -> let Extensible val = gToExtVal @t x in Extensible val+    G.R1 y -> let Extensible val = gToExtVal @t y in Extensible val+  gFromExtVal val =+    let l = fmap G.L1 (gFromExtVal @t val)+        r = fmap G.R1 (gFromExtVal @t val)+    in l <> r++-- | Information to be provided for documenting some @'Extensible' x@.+class Typeable x => ExtensibleHasDoc x where+  -- | Implementation for 'typeDocName' of the corresponding @Extensible@.+  extensibleDocName :: Proxy x -> Text++  -- | Implementation for 'typeDocDependencies' of the corresponding @Extensible@.+  extensibleDocDependencies :: Proxy x -> [SomeTypeWithDoc]+  default extensibleDocDependencies+    :: (Generic x, GTypeHasDoc (G.Rep x))+    => Proxy x -> [SomeTypeWithDoc]+  extensibleDocDependencies = genericTypeDocDependencies++  -- | Overall description of this type.+  extensibleDocMdDescription :: Markdown++-- | Helper which documents single constructor.+class DocumentCtor (ctor :: Ctor) where+  documentCtor :: Proxy ctor -> Markdown+instance ( KnownNat pos, KnownSymbol name, TypeHasDoc param+         , param ~ ExtractCtorField field+         ) =>+         DocumentCtor ('Ctor pos name field) where+  documentCtor _ =+    natVal (Proxy @pos) |+ ": " <> mdBold (build $ symbolValT' @name) <>+    " " <> typeDocMdReference (Proxy @param) (WithinParens True)++instance ( ExtensibleHasDoc x+         , ReifyList DocumentCtor (EnumerateCtors (GetCtors x))+         ) => TypeHasDoc (Extensible x) where+  typeDocName _ = extensibleDocName (Proxy @x)+  typeDocMdReference p (WithinParens wp) =+    let name = typeDocName p+        safeName = case T.find isSpace name of+          Nothing -> name+          Just _+            | wp -> "(" <> name <> ")"+            | otherwise -> name+    in customTypeDocMdReference (safeName, DType p) [] (WithinParens False)+  typeDocDependencies _ = extensibleDocDependencies (Proxy @x)+  typeDocHaskellRep = homomorphicTypeDocHaskellRep+  typeDocMichelsonRep = homomorphicTypeDocMichelsonRep+  typeDocMdDescription = mconcat+    [ extensibleDocMdDescription @x+    , "\n\n"+    , "For extensibility purposes this type is represented as `(idx, pack param)`, \+      \where `idx` is a natural number which designates constructor used to \+      \make up given value, and `param` is the argument carried in that \+      \constructor.\n\n"+    , "Value must be one of:\n\n"+    , mconcat $+        Prelude.map (<> "\n\n") $+        reifyList @Ctor @DocumentCtor @(EnumerateCtors (GetCtors x)) documentCtor+    ]
src/Lorentz/Instr.hs view
@@ -1,8 +1,12 @@ module Lorentz.Instr   ( nop   , drop+  , dropN   , dup   , swap+  , digPeano+  , dig+  , dug   , push   , some   , none@@ -19,6 +23,7 @@   , size   , emptySet   , emptyMap+  , emptyBigMap   , map   , iter   , mem@@ -32,12 +37,13 @@   , loopLeft   , lambda   , exec+  , execute+  , apply   , dip+  , ConstraintDIPNLorentz+  , dipNPeano+  , dipN   , failWith-  , failText-  , failTagged-  , failUsing-  , failUnexpected   , cast   , pack   , unpack@@ -63,7 +69,6 @@   , contract   , transferTokens   , setDelegate-  , createAccount   , createContract   , implicitAccount   , now@@ -78,24 +83,35 @@   , 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 ((\\)) 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-  (Instr(..), Notes(NStar), ToT, Value'(..), checkBigMapConstraint, forbiddenBigMap,-  forbiddenOp)-import Michelson.Text+  (pattern CAR, pattern CDR, ConstraintDIG, ConstraintDIG', ConstraintDIPN, ConstraintDIPN',+  ConstraintDUG, ConstraintDUG', Instr(..), RemFail(..), ToTs, Value'(..), starNotes) import Michelson.Typed.Arith+import Michelson.Typed.Haskell.Value+import Util.Peano+import Util.Type  nop :: s :-> s nop = I Nop@@ -103,15 +119,73 @@ drop :: a & s :-> s drop = I DROP +-- | Drop top @n@ elements from the stack.+dropN ::+  forall (n :: GHC.Nat) (s :: [Kind.Type]).+  -- Note: if we introduce `nPeano ~ ToPeano n` variable,+  -- GHC will complain that this constraint is redundant.+  ( SingI (ToPeano n), KnownPeano (ToPeano n)+  , RequireLongerOrSameLength (ToTs s) (ToPeano n)+  -- ↓ Kinda obvious, but not to GHC.+  , 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 -push :: forall t s . (KnownValue t, NoOperation t, NoBigMap t, IsoValue t) => t -> (s :-> t & s)-push a = I $ forbiddenOp @(ToT t) $ forbiddenBigMap @(ToT t) $ PUSH (toVal a)+-- See a comment about `ConstraintDIPNLorentz'.+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+  )++-- | Version of `dig` which uses Peano number.+-- It is inteded for internal usage in Lorentz.+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 @@ -123,7 +197,7 @@  ifNone   :: (s :-> s') -> (a & s :-> s') -> (Maybe a & s :-> s')-ifNone (I l) (I r) = I (IF_NONE l r)+ifNone = iGenericIf IF_NONE  pair :: a & b & s :-> (a, b) & s pair = I PAIR@@ -142,7 +216,7 @@  ifLeft   :: (a & s :-> s') -> (b & s :-> s') -> (Either a b & s :-> s')-ifLeft (I l) (I r) = I (IF_LEFT l r)+ifLeft = iGenericIf IF_LEFT  nil :: KnownValue p => s :-> List p & s nil = I NIL@@ -152,7 +226,7 @@  ifCons   :: (a & List a & s :-> s') -> (s :-> s') -> (List a & s :-> s')-ifCons (I l) (I r) = I (IF_CONS l r)+ifCons = iGenericIf IF_CONS  size :: SizeOpHs c => c & s :-> Natural & s size = I SIZE@@ -164,15 +238,19 @@          => 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)+  :: (MapOpHs c, IsoMapOpRes c b, HasCallStack)   => (MapOpInpHs c & s :-> b & s) -> (c & s :-> MapOpResHs c b & s)-map (I action) = I (MAP action)+map (iNonFailingCode -> action) = I (MAP action)  iter-  :: (IterOpHs c)+  :: (IterOpHs c, HasCallStack)   => (IterOpElHs c & s :-> s) -> (c & s :-> s)-iter (I action) = I (ITER action)+iter (iNonFailingCode -> action) = I (ITER action)  mem :: MemOpHs c => MemOpKeyHs c & c & s :-> Bool & s mem = I MEM@@ -184,41 +262,98 @@ update = I UPDATE  if_ :: (s :-> s') -> (s :-> s') -> (Bool & s :-> s')-if_ (I l) (I r) = I (IF l r)+if_ = iGenericIf IF  loop :: (s :-> Bool & s) -> (Bool & s :-> s)-loop (I b) = I (LOOP b)+loop (iAnyCode -> b) = I (LOOP b)  loopLeft   :: (a & s :-> Either a b & s) -> (Either a b & s :-> b & s)-loopLeft (I b) = I (LOOP_LEFT b)+loopLeft (iAnyCode -> b) = I (LOOP_LEFT b)  lambda-  :: (KnownValue i, KnownValue o)-  => Lambda i o -> (s :-> Lambda i o & s)-lambda (I l) = I (LAMBDA $ VLam l)+  :: (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 -dip :: forall a s s'. (s :-> s') -> (a & s :-> a & s')-dip (I a) = I (DIP a)+-- | Similar to 'exec' but works for lambdas with arbitrary size of input+-- and output.+--+-- Note that this instruction has its arguments flipped, lambda goes first.+-- This seems to be the only reasonable way to achieve good inference.+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)++-- Helper constraint we need for 'dipN'.+-- The first constraint here is sufficient to make 'dipN' compile.+-- However, it is not enough for good type inference. If we use only the first+-- constraint, '_example' below will not compile because GHC will not be able+-- to deduce type of the input stack for 'unit'.+-- It can only deduce that 'ToTs s0' is empty (where 's0' is input stack), but+-- 'ToTs' is not injective, hence 's0' is ambiguous.+-- So we need both and we merge them into one to avoid a warning about+-- a redundant constraint.+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'+  )++-- | Version of `dipN` which uses Peano number.+-- It is inteded for internal usage in Lorentz.+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 = I FAILWITH+failWith = FI FAILWITH  cast :: KnownValue a => (a & s :-> a & s) cast = I CAST  pack-  :: forall a s. (KnownValue a, NoOperation a, NoBigMap a)+  :: forall a s. (NicePackedValue a)   => a & s :-> ByteString & s-pack = I $ forbiddenOp @(ToT a) $ forbiddenBigMap @(ToT a) PACK+pack = I $ PACK \\ nicePackedValueEvi @a  unpack-  :: forall a s. (KnownValue a, NoOperation a, NoBigMap a)+  :: forall a s. (NiceUnpackedValue a)   => ByteString & s :-> Maybe a & s-unpack = I $ forbiddenOp @(ToT a) $ forbiddenBigMap @(ToT a) UNPACK+unpack = I $ UNPACK \\ niceUnpackedValueEvi @a  concat :: ConcatOpHs c => c & c & s :-> c & s concat = I CONCAT@@ -292,8 +427,8 @@ not :: UnaryArithOpHs Not n => n & s :-> UnaryArithResHs Not n & s not = I NOT -compare :: ArithOpHs Compare n m-        => n & m & s :-> ArithResHs Compare n m & s+compare :: ArithOpHs Compare n n+        => n & n & s :-> ArithResHs Compare n n & s compare = I COMPARE  eq0 :: UnaryArithOpHs Eq' n => n & s :-> UnaryArithResHs Eq' n & s@@ -317,36 +452,35 @@ int :: Natural & s :-> Integer & s int = I INT -self :: forall cp s . s :-> ContractAddr cp & s-self = I SELF+self :: forall p s . NiceParameter p => s :-> ContractRef p & s+self = I SELF \\ niceParameterEvi @p -contract :: (KnownValue p) => Address & s :-> Maybe (ContractAddr p) & s-contract = I (CONTRACT NStar)+-- TODO [TM-280]: provide proper implementation.+contract+  :: forall p s.+      (NiceParameter p)+  => Address & s :-> Maybe (ContractRef p) & s+contract = I (CONTRACT starNotes def) \\ niceParameterEvi @p  transferTokens-  :: forall p s. (KnownValue p, NoOperation p, NoBigMap p)-  => p & Mutez & ContractAddr p & s :-> Operation & s-transferTokens = I $ forbiddenOp @(ToT p) $ forbiddenBigMap @(ToT p) TRANSFER_TOKENS+  :: 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 -createAccount :: KeyHash & Maybe KeyHash & Bool & Mutez & s-              :-> Operation & Address & s-createAccount = I CREATE_ACCOUNT-- createContract-  :: forall p g s. (KnownValue p, NoOperation p, KnownValue g, NoOperation g-                   , NoBigMap p, CanHaveBigMap g)-  => '[(p, g)] :-> '[(List Operation, g)]-  -> KeyHash & Maybe KeyHash & Bool & Bool & Mutez & g & s+  :: forall p g s. (NiceStorage g, ParameterEntryPoints p)+  => Contract p g+  -> Maybe KeyHash & Mutez & g & s   :-> Operation & Address & s-createContract (I c) =-  I $ forbiddenOp @(ToT p) $ forbiddenOp @(ToT g) $-  forbiddenBigMap @(ToT p) $ checkBigMapConstraint @(ToT g) $ CREATE_CONTRACT c+createContract cntrc =+  I $ CREATE_CONTRACT (compileLorentzContract cntrc)+    \\ niceParameterEvi @p+    \\ niceStorageEvi @g -implicitAccount :: KeyHash & s :-> ContractAddr () & s+implicitAccount :: KeyHash & s :-> ContractRef () & s implicitAccount = I IMPLICIT_ACCOUNT  now :: s :-> Timestamp & s@@ -373,6 +507,7 @@ 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 @@ -385,9 +520,27 @@ sender :: s :-> Address & s sender = I SENDER -address :: ContractAddr a & s :-> Address & s+address :: ContractRef a & s :-> Address & s address = I ADDRESS +chainId :: s :-> ChainId & s+chainId = I CHAIN_ID++-- | Execute given instruction on truncated stack.+--+-- This instruction requires you to specify the piece of stack to truncate+-- as type argument.+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+ ---------------------------------------------------------------------------- -- Non-canonical instructions ----------------------------------------------------------------------------@@ -418,31 +571,18 @@   -> k & UpdOpParamsHs c & c & s :-> c & s updateNew mkErr = failingWhenPresent mkErr # update --- | Fail with a given message.-failText :: MText -> s :-> t-failText msg = push msg # failWith---- | Fail with a given message and the top of the current stack.-failTagged :: (KnownValue a) => MText -> a & s :-> t-failTagged tag = push tag # pair # failWith---- | Fail with the given Haskell value.-failUsing-  :: (IsoValue a, KnownValue a, NoOperation a, NoBigMap a)-  => a -> s :-> t-failUsing err = push err # failWith---- | Fail, providing a reference to the place in the code where--- this function is called.------ Like 'error' in Haskell code, this instruction is for internal errors only.-failUnexpected :: HasCallStack => MText -> s :-> t-failUnexpected msg =-  failText $ [mt|Unexpected failure: |] <> msg <> [mt|\n|]-          <> mkMTextCut (toText $ prettyCallStack callStack)- 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+  -- | Retain the value only if it is not zero.+  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
src/Lorentz/Macro.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}  -- | Common Michelson macros defined using Lorentz syntax. module Lorentz.Macro@@ -31,8 +32,8 @@   -- They differ from the same macros in Michelson, because those   -- macros use FAIL macro which is not informative (fails with unit).   -- If you __really__ want Michelson versions (maybe to produce exact-  -- copy of an existing contract), you can pass empty string, then-  -- FAILWITH will be called with unit, not empty string.+  -- copy of an existing contract), you can pass 'UnspecifiedError', then+  -- FAILWITH will be called with unit.   , assert   , assertEq0   , assertNeq0@@ -53,11 +54,10 @@   , assertUsing    -- * Syntactic Conveniences-  , dipX   , dropX   , cloneX   , duupX-  , elevateX+  , framedN   , caar   , cadr   , cdar@@ -83,53 +83,71 @@   , Void_ (..)   , VoidResult(..)   , view_+  , mkView   , void_   , mkVoid++  -- * Buildable utils for additional Morley macros+  , buildView+  , buildViewTuple++  -- * Macros for working with @contract@-like types+  , pushContractRef+  , pickFutureContract   ) where  import Prelude hiding (compare, drop, some, swap)  import qualified Data.Kind as Kind import Data.Vinyl.TypeLevel (Nat(..))-import GHC.TypeNats (type (+), type (-))+import Fmt (Buildable(..), Builder, pretty, tupleF, (+|), (|+))+import Fmt.Internal.Tuple (TupleF)+import GHC.TypeNats (type (-)) import qualified GHC.TypeNats as GHC (Nat)  import Lorentz.Arith import Lorentz.Base-import Lorentz.Constraints import Lorentz.Coercions+import Lorentz.Constraints+import Lorentz.Doc+import Lorentz.Errors+import Lorentz.Ext (stackType) import Lorentz.Instr import Lorentz.Value+import Michelson.Typed (ConstraintDIG', ConstraintDIPN', T, typeDocDependencies') import Michelson.Typed.Arith import Michelson.Typed.Haskell.Value+import Michelson.Typed (Instr (..), sepcName, starNotes)+import Util.Markdown import Util.Peano+import Util.Type  ---------------------------------------------------------------------------- -- Compare ---------------------------------------------------------------------------- -eq :: (ArithOpHs Compare n m, UnaryArithOpHs Eq' (ArithResHs Compare n m))-   => n & m & s :-> (UnaryArithResHs Eq' (ArithResHs Compare n m)) & s+eq :: (ArithOpHs Compare n n)+   => n & n & s :-> (UnaryArithResHs Eq' (ArithResHs Compare n n)) & s eq = compare # eq0 -neq :: (ArithOpHs Compare n m, UnaryArithOpHs Neq (ArithResHs Compare n m))-   => n & m & s :-> (UnaryArithResHs Neq (ArithResHs Compare n m)) & s+neq :: (ArithOpHs Compare n n)+   => n & n & s :-> (UnaryArithResHs Neq (ArithResHs Compare n n)) & s neq = compare # neq0 -gt :: (ArithOpHs Compare n m, UnaryArithOpHs Gt (ArithResHs Compare n m))-   => n & m & s :-> (UnaryArithResHs Gt (ArithResHs Compare n m)) & s+gt :: (ArithOpHs Compare n n)+   => n & n & s :-> (UnaryArithResHs Gt (ArithResHs Compare n n)) & s gt = compare # gt0 -le :: (ArithOpHs Compare n m, UnaryArithOpHs Le (ArithResHs Compare n m))-   => n & m & s :-> (UnaryArithResHs Le (ArithResHs Compare n m)) & s+le :: (ArithOpHs Compare n n)+   => n & n & s :-> (UnaryArithResHs Le (ArithResHs Compare n n)) & s le = compare # le0 -ge :: (ArithOpHs Compare n m, UnaryArithOpHs Ge (ArithResHs Compare n m))-   => n & m & s :-> (UnaryArithResHs Ge (ArithResHs Compare n m)) & s+ge :: (ArithOpHs Compare n n)+   => n & n & s :-> (UnaryArithResHs Ge (ArithResHs Compare n n)) & s ge = compare # ge0 -lt :: (ArithOpHs Compare n m, UnaryArithOpHs Lt (ArithResHs Compare n m))-   => n & m & s :-> (UnaryArithResHs Lt (ArithResHs Compare n m)) & s+lt :: (ArithOpHs Compare n n)+   => n & n & s :-> (UnaryArithResHs Lt (ArithResHs Compare n n)) & s lt = compare # lt0  type IfCmp0Constraints a op =@@ -165,39 +183,39 @@   => (s :-> s') -> (s :-> s') -> (a & s :-> s') ifGe0 l r = ge0 # if_ l r -type IfCmpXConstraints a b op =-  (Typeable a, Typeable b, ArithOpHs Compare a b-  , UnaryArithOpHs op (ArithResHs Compare a b)-  , UnaryArithResHs op (ArithResHs Compare a b) ~ Bool)+type IfCmpXConstraints a op =+  (Typeable a, ArithOpHs Compare a a+  , UnaryArithOpHs op (ArithResHs Compare a a)+  , UnaryArithResHs op (ArithResHs Compare a a) ~ Bool)  ifEq-  :: (IfCmpXConstraints a b Eq')-  => (s :-> s') -> (s :-> s') -> (a & b & s :-> s')+  :: (IfCmpXConstraints a Eq')+  => (s :-> s') -> (s :-> s') -> (a & a & s :-> s') ifEq l r = eq # if_ l r  ifNeq-  :: (IfCmpXConstraints a b Neq)-  => (s :-> s') -> (s :-> s') -> (a & b & s :-> s')+  :: (IfCmpXConstraints a Neq)+  => (s :-> s') -> (s :-> s') -> (a & a & s :-> s') ifNeq l r = neq # if_ l r  ifLt-  :: (IfCmpXConstraints a b Lt)-  => (s :-> s') -> (s :-> s') -> (a & b & s :-> s')+  :: (IfCmpXConstraints a Lt)+  => (s :-> s') -> (s :-> s') -> (a & a & s :-> s') ifLt l r = lt # if_ l r  ifGt-  :: (IfCmpXConstraints a b Gt)-  => (s :-> s') -> (s :-> s') -> (a & b & s :-> s')+  :: (IfCmpXConstraints a Gt)+  => (s :-> s') -> (s :-> s') -> (a & a & s :-> s') ifGt l r = gt # if_ l r  ifLe-  :: (IfCmpXConstraints a b Le)-  => (s :-> s') -> (s :-> s') -> (a & b & s :-> s')+  :: (IfCmpXConstraints a Le)+  => (s :-> s') -> (s :-> s') -> (a & a & s :-> s') ifLe l r = le # if_ l r  ifGe-  :: (IfCmpXConstraints a b Ge)-  => (s :-> s') -> (s :-> s') -> (a & b & s :-> s')+  :: (IfCmpXConstraints a Ge)+  => (s :-> s') -> (s :-> s') -> (a & a & s :-> s') ifGe l r = ge # if_ l r  ----------------------------------------------------------------------------@@ -214,65 +232,59 @@ -- Assertions ---------------------------------------------------------------------------- --- Helper function, see Haddock comment in the export list.-assertionFailed :: MText -> whatever :-> anything-assertionFailed reason-  | null reason = fail_-  | otherwise = failText reason--assert :: MText -> Bool & s :-> s-assert reason = if_ nop (assertionFailed reason)+assert :: IsError err => err -> Bool & s :-> s+assert reason = if_ nop (failUsing reason) -assertEq0 :: IfCmp0Constraints a Eq' => MText -> a & s :-> s-assertEq0 reason = ifEq0 nop (assertionFailed reason)+assertEq0 :: (IfCmp0Constraints a Eq', IsError err) => err -> a & s :-> s+assertEq0 reason = ifEq0 nop (failUsing reason) -assertNeq0 :: IfCmp0Constraints a Neq => MText -> a & s :-> s-assertNeq0 reason = ifNeq0 nop (assertionFailed reason)+assertNeq0 :: (IfCmp0Constraints a Neq, IsError err) => err -> a & s :-> s+assertNeq0 reason = ifNeq0 nop (failUsing reason) -assertLt0 :: IfCmp0Constraints a Lt => MText -> a & s :-> s-assertLt0 reason = ifLt0 nop (assertionFailed reason)+assertLt0 :: (IfCmp0Constraints a Lt, IsError err) => err -> a & s :-> s+assertLt0 reason = ifLt0 nop (failUsing reason) -assertGt0 :: IfCmp0Constraints a Gt => MText -> a & s :-> s-assertGt0 reason = ifGt0 nop (assertionFailed reason)+assertGt0 :: (IfCmp0Constraints a Gt, IsError err) => err -> a & s :-> s+assertGt0 reason = ifGt0 nop (failUsing reason) -assertLe0 :: IfCmp0Constraints a Le => MText -> a & s :-> s-assertLe0 reason = ifLe0 nop (assertionFailed reason)+assertLe0 :: (IfCmp0Constraints a Le, IsError err) => err -> a & s :-> s+assertLe0 reason = ifLe0 nop (failUsing reason) -assertGe0 :: IfCmp0Constraints a Ge => MText -> a & s :-> s-assertGe0 reason = ifGe0 nop (assertionFailed reason)+assertGe0 :: (IfCmp0Constraints a Ge, IsError err) => err -> a & s :-> s+assertGe0 reason = ifGe0 nop (failUsing reason) -assertEq :: IfCmpXConstraints a b Eq' => MText -> a & b & s :-> s-assertEq reason = ifEq nop (assertionFailed reason)+assertEq :: (IfCmpXConstraints a Eq', IsError err) => err -> a & a & s :-> s+assertEq reason = ifEq nop (failUsing reason) -assertNeq :: IfCmpXConstraints a b Neq => MText -> a & b & s :-> s-assertNeq reason = ifNeq nop (assertionFailed reason)+assertNeq :: (IfCmpXConstraints a Neq, IsError err) => err -> a & a & s :-> s+assertNeq reason = ifNeq nop (failUsing reason) -assertLt :: IfCmpXConstraints a b Lt => MText -> a & b & s :-> s-assertLt reason = ifLt nop (assertionFailed reason)+assertLt :: (IfCmpXConstraints a Lt, IsError err) => err -> a & a & s :-> s+assertLt reason = ifLt nop (failUsing reason) -assertGt :: IfCmpXConstraints a b Gt => MText -> a & b & s :-> s-assertGt reason = ifGt nop (assertionFailed reason)+assertGt :: (IfCmpXConstraints a Gt, IsError err) => err -> a & a & s :-> s+assertGt reason = ifGt nop (failUsing reason) -assertLe :: IfCmpXConstraints a b Le => MText -> a & b & s :-> s-assertLe reason = ifLe nop (assertionFailed reason)+assertLe :: (IfCmpXConstraints a Le, IsError err) => err -> a & a & s :-> s+assertLe reason = ifLe nop (failUsing reason) -assertGe :: IfCmpXConstraints a b Ge => MText -> a & b & s :-> s-assertGe reason = ifGe nop (assertionFailed reason)+assertGe :: (IfCmpXConstraints a Ge, IsError err) => err -> a & a & s :-> s+assertGe reason = ifGe nop (failUsing reason) -assertNone :: MText -> Maybe a & s :-> s-assertNone reason = ifNone nop (assertionFailed reason)+assertNone :: IsError err => err -> Maybe a & s :-> s+assertNone reason = ifNone nop (failUsing reason) -assertSome :: MText -> Maybe a & s :-> a & s-assertSome reason = ifNone (assertionFailed reason) nop+assertSome :: IsError err => err -> Maybe a & s :-> a & s+assertSome reason = ifNone (failUsing reason) nop -assertLeft :: MText -> Either a b & s :-> a & s-assertLeft reason = ifLeft nop (assertionFailed reason)+assertLeft :: IsError err => err -> Either a b & s :-> a & s+assertLeft reason = ifLeft nop (failUsing reason) -assertRight :: MText -> Either a b & s :-> b & s-assertRight reason = ifLeft (assertionFailed reason) nop+assertRight :: IsError err => err -> Either a b & s :-> b & s+assertRight reason = ifLeft (failUsing reason) nop  assertUsing-  :: (IsoValue a, KnownValue a, NoOperation a, NoBigMap a)+  :: IsError a   => a -> Bool & s :-> s assertUsing err = if_ nop $ failUsing err @@ -280,42 +292,15 @@ -- Syntactic Conveniences ---------------------------------------------------------------------------- -type family Above (n :: Peano) s where-  Above  'Z _s = '[]-  Above ('S n) (a ': s) = (a ': Above n s)--class DipX (n :: Peano) (head :: [Kind.Type]) (s :: [Kind.Type]) (s' :: [Kind.Type]) where-  dipXImpl :: s :-> s' -> head ++ s :-> head ++ s'-instance DipX 'Z '[] s s' where-  dipXImpl op = op-instance DipX n h s s' => DipX ('S n) (a ': h) s s' where-  dipXImpl = dip . dipXImpl @n @h---- Type family, that is necessary for DipX-type family (++) (l :: [a]) (r :: [a]) where-  '[] ++ r = r-  (l ': ls) ++ r = l ': (ls ++ r)---- | @DII+P@ macro. For example, `dipX @3` is `DIIIP`.-dipX-  :: forall (n :: GHC.Nat) inp out s s'.-  (DipX (ToPeano n) (Above (ToPeano n) inp) s s'-  , ((Above (ToPeano n) inp) ++ s) ~ inp-  , ((Above (ToPeano n) inp) ++ s') ~ out)-  => (s :-> s') -> inp :-> out-dipX = dipXImpl @(ToPeano n) @(Above (ToPeano n) inp)- -- | Custom Lorentz macro that drops element with given index -- (starting from 0) from the stack. dropX   :: forall (n :: GHC.Nat) a inp out s s'.-  ( DipX (ToPeano n) (Above (ToPeano n) inp) s s'-  , ((Above (ToPeano n) inp) ++ s) ~ inp-  , ((Above (ToPeano n) inp) ++ s') ~ out+  ( ConstraintDIPNLorentz (ToPeano n) inp out s s'   , s ~ (a ': s')   )   => inp :-> out-dropX = dipX @n @inp @out @s @s' drop+dropX = dipN @n @inp @out @s @s' drop  class CloneX (n :: Peano) a s where   type CloneXT n a s :: [Kind.Type]@@ -335,43 +320,81 @@   => a & s :-> CloneXT (ToPeano n) a s cloneX = cloneXImpl @(ToPeano n) -class DuupX (n :: Peano) (s :: [Kind.Type]) (a :: Kind.Type) where-  duupXImpl :: s :-> a & s+-- | Kind-agnostic constraint for duupX+type DuupXConstraint' kind (n :: Peano)+  (s :: [kind]) (a :: kind) (s1 :: [kind]) (tail :: [kind]) =+  ( tail ~ Drop ('S n) s+  , ConstraintDIPN' kind n s s1 (a ': tail) (a ': a ': tail)+  , ConstraintDIG' kind n s1 (a ': s) a+  ) -instance DuupX ('S 'Z) (a & xs) a where+-- | Constraint for duupX that combines kind-agnostic constraint for+-- Lorentz (Haskell) types and for our typed Michelson.+type ConstraintDuupXLorentz (n :: Peano)+  (s :: [Kind.Type]) (a :: Kind.Type)+  (s1 :: [Kind.Type]) (tail :: [Kind.Type]) =+  ( DuupXConstraint' T n (ToTs s) (ToT a) (ToTs s1) (ToTs tail)+  , DuupXConstraint' Kind.Type n s a s1 tail+  )++class DuupX (n :: Peano) (s :: [Kind.Type]) (a :: Kind.Type) s1 tail where+  duupXImpl :: s :-> a ': s++instance {-# OVERLAPPING #-} (s ~ (a ': xs)) => DuupX ('S 'Z) s a s1 tail where   duupXImpl = dup -instance DuupX ('S n) xs a => DuupX ('S ('S n)) (x & xs) a where-  duupXImpl = dip (duupXImpl @('S n) @xs @a) # swap+instance {-# OVERLAPPING #-} DuupX ('S ('S 'Z)) (b ': a ': xs) a s1 tail where+  duupXImpl = dip dup # swap +instance {-# OVERLAPPABLE #-} (ConstraintDuupXLorentz ('S ('S n)) s a s1 tail) =>+  DuupX ('S ('S ('S n))) s a s1 tail where+  duupXImpl =+    -- 'stackType' helps GHC deduce types+    dipNPeano @('S ('S n)) (dup # stackType @(a ': a ': tail)) #+    digPeano @('S ('S n))+ -- | @DUU+P@ macro. For example, `duupX @3` is `DUUUP`, it puts -- the 3-rd (starting from 1) element to the top of the stack.-duupX-  :: forall (n :: GHC.Nat) inp .-  ( DuupX (ToPeano n) inp (At (ToPeano (n - 1)) inp)+-- Note that it is implemented differently for `n ≤ 2` and for `n > 2`.+-- In the latter case it is implemented using `dipN`, `dig` and `dup`.+-- In the former case it uses specialized versions.+-- There is also a minor difference with the implementation of `DUU*P` in+-- Michelson.+-- They implement `DUUUUP` as `DIP 3 { DUP }; DIG 4`.+-- We implement it as `DIP 3 { DUP }; DIG 3`. These are equivalent.+-- Our version is supposedly cheaper, at least it should be packed+-- more efficiently due to the way numbers are packed.+duupX :: forall (n :: GHC.Nat) a (s :: [Kind.Type]) (s1 :: [Kind.Type]) (tail :: [Kind.Type]).+  ( ConstraintDuupXLorentz (ToPeano (n - 1)) s a s1 tail+  , DuupX (ToPeano n) s a s1 tail   )-  => inp :-> (At (ToPeano (n - 1)) inp) & inp-duupX = duupXImpl @(ToPeano n) @inp @(At (ToPeano (n - 1)) inp)+  => s :-> a ': s+duupX = duupXImpl @(ToPeano n) @s @a @s1 @tail+  where+    _example ::+      '[ Integer, (), Bool ] :->+      '[ Bool, Integer, (), Bool ]+    _example = duupX @3 --- | Move item with given index (starting from 0) to the top of the stack.+-- | Version of 'framed' which accepts number of elements on input stack+-- which should be preserved. ----- TODO: probably it can be implemented more efficiently, so if we--- ever want to optimize gas consumption we can rewrite it.--- It only makes sense if it's applied to a relatively large index.-elevateX-  :: forall (n :: GHC.Nat) inp out s a.-  ( DuupX (ToPeano (1 + n)) inp a-  , DipX (ToPeano (n + 1)) (Above (ToPeano (n + 1)) (a : inp)) (a : s) s-  , (a ': (Above (ToPeano n) inp) ++ s) ~ out-  , a ~ At (ToPeano n) inp--  -- These 3 constraints must hold if the above holds, but GHC can't deduce it.-  -- Btw, last constraint must always hold.-  , (Above (ToPeano (n + 1)) (a ': inp) ++ (a ': s)) ~ (a ': inp)-  , (Above (ToPeano (n + 1)) (a : inp) ++ s) ~ (a : (Above (ToPeano n) inp ++ s))-  , ((1 + n) - 1) ~ n-  ) => inp :-> out-elevateX = duupX @(1 + n) @inp # dropX @(n + 1) @a @(a ': inp) @out @(a ': s) @s+-- You can treat this macro as calling a Michelson function with given number+-- of arguments.+framedN+  :: forall n nNat s i i' o o'.+     ( nNat ~ ToPeano n+     , i' ~ Take nNat i, s ~ Drop nNat i+     , i ~ (i' ++ s), o ~ (o' ++ s)+     , KnownList i', KnownList o'+     )+  => (i' :-> o') -> (i :-> o)+framedN = framed @s+  where+  _example+    :: [Integer, Natural] :-> '[ByteString]+    -> Integer : Natural : () : s :-> ByteString : () : s+  _example = framedN @2  papair :: a & b & c & s :-> ((a, b), c) & s papair = pair # pair@@ -476,17 +499,49 @@ -- | @view@ type synonym as described in A1. data View (a :: Kind.Type) (r :: Kind.Type) = View   { viewParam :: a-  , viewCallbackTo :: ContractAddr (a, Maybe r)-  } deriving stock Generic+  , viewCallbackTo :: ContractRef r+  } deriving stock (Eq, Show, Generic)     deriving anyclass IsoValue +instance Each [Typeable, TypeHasDoc] [a, r] => TypeHasDoc (View a r) where+  typeDocMdDescription =+    "`View a r` accepts an argument of type `a` and callback contract \+    \which accepts `r` and returns result via calling that contract.\n\+    \Read more in [A1 conventions document](https://gitlab.com/tzip/tzip/blob/master/A/A1.md#view-entry-points)."+  typeDocMdReference = poly2TypeDocMdReference+  typeDocDependencies p =+    genericTypeDocDependencies p <>+    [SomeTypeWithDoc (Proxy @()), SomeTypeWithDoc (Proxy @Integer)]+  typeDocHaskellRep =+    haskellRepNoFields $ concreteTypeDocHaskellRep @(View () Integer)+  typeDocMichelsonRep =+    concreteTypeDocMichelsonRep @(View () Integer)++instance {-# OVERLAPPABLE #-} Buildable a => Buildable (View a r) where+  build = buildView build++instance {-# OVERLAPPING  #-} Buildable (View () r) where+  build = buildView $ const "()"+++buildViewTuple :: TupleF a => View a r -> Builder+buildViewTuple = buildView tupleF++buildView :: (a -> Builder) -> View a r -> Builder+buildView bfp (View {..}) =+  "(View param: " +| bfp viewParam |+ " callbackTo: " +| viewCallbackTo|+ ")"++-- | Polymorphic version of 'View' constructor.+mkView :: ToContractRef r contract => a -> contract -> View a r+mkView a c = View a (toContractRef c)+ view_ ::-     (KnownValue a, KnownValue r, NoOperation (a, r), NoBigMap (a, r))+     (NiceParameter r)   => (forall s0. (a, storage) & s0 :-> r : s0)   -> View a r & storage & s :-> (List Operation, storage) & s view_ code =   coerce_ #-  unpair # dip (duupX @2) # dup # dip (pair # code # some) # pair # dip amount #+  unpair # dip (duupX @2) # pair # code # dip amount #   transferTokens # nil # swap # cons # pair  -- | @void@ type synonym as described in A1.@@ -498,21 +553,121 @@   } deriving stock Generic     deriving anyclass IsoValue +instance Each [Typeable, TypeHasDoc] [a, r] => TypeHasDoc (Void_ a r) where+  typeDocName _ = "Void"+  typeDocMdDescription =+    "`Void a r` accepts an argument of type `a` and returns a value of type \+    \`r` as contract error. To comply with general mechanism of contracts \+    \custom errors, void entrypoints execute `FAILWITH` instruction on \+    \`(\"VoidResult\", r)` value, where `r` is the actual return value of the \+    \entrypoint.\n\+    \Read more in [A1 conventions document](https://gitlab.com/tzip/tzip/blob/master/A/A1.md#void-entry-points)."+  typeDocMdReference tp =+    -- Avoiding trailing underscore+    customTypeDocMdReference+      ("Void", DType tp)+      [ DType (Proxy @a)+      , DType (Proxy @r)+      ]+  typeDocDependencies p =+    genericTypeDocDependencies p <>+    [SomeTypeWithDoc (Proxy @()), SomeTypeWithDoc (Proxy @Integer)]+  typeDocHaskellRep p = do+    (_, rhs) <- haskellRepNoFields (concreteTypeDocHaskellRep @(Void_ () Integer)) p+    return (Just "Void () Integer", rhs)+  typeDocMichelsonRep p =+    let (_, rhs) = concreteTypeDocMichelsonRep @(Void_ () Integer) p+    in (Just "Void () Integer", rhs)++instance Buildable a => Buildable (Void_ a b) where+  build Void_ {..} = "(Void param: " +| voidParam |+ ")"+ -- | Newtype over void result type used in tests to -- distinguish successful void result from other errors. -- -- Usage example: -- lExpectFailWith (== VoidResult roleMaster)`+--+-- This error is special - it can contain arguments of different types+-- depending on entrypoint which raises it. newtype VoidResult r = VoidResult { unVoidResult :: r }-  deriving newtype (Eq, IsoValue)+  deriving stock (Generic)+  deriving newtype (Eq) +voidResultTag :: MText+voidResultTag = [mt|VoidResult|]++type VoidResultRep r = (MText, r)++instance (TypeHasDoc r, IsError (VoidResult r)) => TypeHasDoc (VoidResult r) where+  typeDocMdDescription = typeDocMdDescriptionReferToError @(VoidResult r)+  typeDocMdReference = poly1TypeDocMdReference+  typeDocHaskellRep = concreteTypeDocHaskellRepUnsafe @(VoidResultRep Integer)+  typeDocMichelsonRep = concreteTypeDocMichelsonRepUnsafe @(VoidResultRep Integer)++instance (Typeable r, NiceConstant r, ErrorHasDoc (VoidResult r)) =>+         IsError (VoidResult r) where+  errorToVal (VoidResult e) cont =+    withDict (niceConstantEvi @r) $+    isoErrorToVal @(VoidResultRep r) (voidResultTag, e) cont+  errorFromVal fullErr =+    isoErrorFromVal fullErr >>= \((tag, e) :: VoidResultRep r) ->+      if tag == voidResultTag+      then pure $ VoidResult e+      else Left $ "Error mismatch, expected VoidResult, got " <> pretty tag++instance TypeHasDoc r => ErrorHasDoc (VoidResult r) where+  errorDocName = "VoidResult"+  errorDocMdCause =+    "Call to entrypoint has succeeded, reporting returned value as error.\n\+    \As Tezos contracts normally do not produce any output (not counting storage \+    \update), this is the simplest way to return something to the caller in \+    \read-only entrypoints."+  errorDocHaskellRep =+    mdTicked ("(\"" <> pretty (voidResultTag) <> "\", " <> "<return value>" <> ")")+  errorDocDependencies =+    typeDocDependencies' (Proxy @MText) <> typeDocDependencies' (Proxy @r)++instance CustomErrorNoIsoValue (VoidResult r) => IsoValue (VoidResult r) where+  type ToT (VoidResult r) = CustomErrorNoIsoValue (VoidResult r)+  toVal = error "impossible"+  fromVal = error "impossible"+ mkVoid :: forall b a. a -> Void_ a b mkVoid a = Void_ a nop  void_   :: forall a b s s' anything.-      (KnownValue b)+      (IsError (VoidResult b), KnownValue b)   => a & s :-> b & s' -> Void_ a b & s :-> anything void_ code =+  doc (DThrows (Proxy @(VoidResult b))) #   coerce_ @_ @(_, Lambda b b) #-  unpair # swap # dip code # swap # exec # coerce_ @b @(VoidResult b) # failWith+  unpair # swap # dip code # swap # exec #+  push voidResultTag # pair # failWith @(MText, b)++-- | Turn 'FutureContract' into actual 'contract'.+--+-- This requires contracts lookup and may fail.+pickFutureContract+  :: NiceParameter p+  => FutureContract p : s :-> Maybe (ContractRef p) : s+pickFutureContract = coerce_ # contract++-- | Push a value of @contract@ type.+--+-- Doing this via 'push' instruction is not possible, so we need to perform+-- extra actions here.+--+-- Aside from @contract@ value itself you will need to specify which error to+-- throw in case this value is not valid.+pushContractRef+  :: NiceParameter arg+  => (forall s0. Address : s :-> s0)+  -> ContractRef arg+  -> (s :-> ContractRef arg : s)+pushContractRef onContractNotFound (ContractRef addr sepc :: ContractRef arg) =+  withDict (niceParameterEvi @arg) $+    push addr # dup #+    I (CONTRACT starNotes (sepcName sepc)) #+    ifNone onContractNotFound (dip drop)
+ src/Lorentz/Pack.hs view
@@ -0,0 +1,26 @@+-- | Packing utilities.+module Lorentz.Pack+  ( lPackValue+  , lUnpackValue+  ) where++import Data.Constraint ((\\))++import Lorentz.Constraints+import Michelson.Interpret.Pack+import Michelson.Interpret.Unpack+import Michelson.Typed++lPackValue+  :: forall a.+     (NicePackedValue a)+  => a -> ByteString+lPackValue =+  packValue' . toVal \\ nicePackedValueEvi @a++lUnpackValue+  :: forall a.+     (NiceUnpackedValue a)+  => ByteString -> Either UnpackError a+lUnpackValue =+  fmap fromVal . unpackValue' \\ niceUnpackedValueEvi @a
src/Lorentz/Prelude.hs view
@@ -1,6 +1,7 @@ -- | Commonly used parts of regular Prelude. module Lorentz.Prelude   ( ($)+  , (.)   , type ($)   , Eq   , Ord@@ -9,6 +10,10 @@   , Monoid (..)   , Generic   , Text+  , Either (..)+  , Maybe (..)+  , Proxy (..)   , fromString   , undefined+  , error   ) where
+ src/Lorentz/Print.hs view
@@ -0,0 +1,34 @@+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++-- | Printing lorentz contracts.+module Lorentz.Print+  ( printLorentzValue+  , printLorentzContract+  ) where+++import Lorentz.Base+import Lorentz.Constraints+import Lorentz.EntryPoints+import Lorentz.Run+import Michelson.Printer (printTypedFullContract, printTypedValue)+import Michelson.Typed (toVal)++-- | Pretty-print a Haskell value as Michelson one.+printLorentzValue+  :: forall v.+    (NicePrintedValue v)+  => Bool -> v -> LText+printLorentzValue forceSingleLine =+  withDict (nicePrintedValueEvi @v) $+    printTypedValue forceSingleLine . toVal++-- | Pretty-print a Lorentz contract into Michelson code.+printLorentzContract+  :: forall cp st.+     ( NiceParameter cp, NiceStorage st+     , ParameterEntryPoints cp+     )+  => Bool -> Contract cp st -> LText+printLorentzContract forceSingleLine =+  printTypedFullContract forceSingleLine . compileLorentzContract
src/Lorentz/Rebinded.hs view
@@ -48,12 +48,12 @@   IsNotZero :: (UnaryArithOpHs Eq' a, UnaryArithResHs Eq' a ~ Bool)          => Condition s (a ': s) s s -  IsEq :: IfCmpXConstraints a b Eq' => Condition s (a ': b ': s) s s-  IsNeq :: IfCmpXConstraints a b Neq => Condition s (a ': b ': s) s s-  IsLt :: IfCmpXConstraints a b Lt => Condition s (a ': b ': s) s s-  IsGt :: IfCmpXConstraints a b Gt => Condition s (a ': b ': s) s s-  IsLe :: IfCmpXConstraints a b Le => Condition s (a ': b ': s) s s-  IsGe :: IfCmpXConstraints a b Ge => Condition s (a ': b ': s) s s+  IsEq :: IfCmpXConstraints a Eq' => Condition s (a ': a ': s) s s+  IsNeq :: IfCmpXConstraints a Neq => Condition s (a ': a ': s) s s+  IsLt :: IfCmpXConstraints a Lt => Condition s (a ': a ': s) s s+  IsGt :: IfCmpXConstraints a Gt => Condition s (a ': a ': s) s s+  IsLe :: IfCmpXConstraints a Le => Condition s (a ': a ': s) s s+  IsGe :: IfCmpXConstraints a Ge => Condition s (a ': a ': s) s s  -- | Defines semantics of @if ... then ... else ...@ construction. ifThenElse
src/Lorentz/Referenced.hs view
@@ -152,11 +152,6 @@ part of stack to contain no elements of type "X", and this is annoying at least because it ruins modularity. -For now I suggest to use these instructions only in contract code directly, and-if you need to extract a set of instructions to a reusable function polymorphic-over stack tail then it will probably be small enough to use just plain-instructions.--If this module is in demand, I hope we will find a way to resolve this issue.+This issue can be resolved with using 'framed' instruction wrapper and family.  -}
+ src/Lorentz/Run.hs view
@@ -0,0 +1,77 @@+module Lorentz.Run+  ( compileLorentz+  , compileLorentzContract+  , interpretLorentzInstr+  , interpretLorentzLambda+  , analyzeLorentz+  ) where++import Data.Constraint ((\\))+import Data.Vinyl.Core (Rec(..))+import Fmt (pretty)++import Lorentz.Base+import Lorentz.Constraints+import Lorentz.EntryPoints+import Michelson.Analyzer (AnalyzerRes, analyze)+import Michelson.Interpret+import Michelson.Typed+  (FullContract(..), Instr(..), IsoValue, IsoValuesStack(..), ToT, ToTs, isStar,+  mkParamNotes, starNotes)++-- | For use outside of Lorentz.+compileLorentz :: (inp :-> out) -> Instr (ToTs inp) (ToTs out)+compileLorentz = iAnyCode++-- | Version of 'compileLorentz' specialized to instruction corresponding to+-- contract code.+compileLorentzContract+  :: forall cp st.+     (NiceParameter cp, NiceStorage st, ParameterEntryPoints cp)+  => Contract cp st -> FullContract (ToT cp) (ToT st)+compileLorentzContract contract =+  FullContract+  { fcCode = if isStar cpNotes+      then  -- We have no annotations. Print contract as such.+        compileLorentz contract+      else  -- If we have some annotations, erase them.+        compileLorentz (I CAST # contract :: Contract cp st)+  , fcParamNotesSafe = case mkParamNotes cpNotes of+      Right n -> n+      Left e -> error $+        -- TODO [TM-280]: make sure Lorentz actually does not produce such+        "Lorentz unexpectedly compiled into contract with \+        \illegal parameter declaration: " <> show cpNotes <> "\n" <>+        "Reason: " <> pretty e+  , fcStoreNotes = starNotes+  } \\ niceParameterEvi @cp+    \\ niceStorageEvi @st+  where+    cpNotes = pesNotes (parameterEntryPoints @cp)++-- | Interpret a Lorentz instruction, for test purposes.+interpretLorentzInstr+  :: (IsoValuesStack inp, IsoValuesStack out)+  => ContractEnv+  -> inp :-> out+  -> Rec Identity inp+  -> Either MichelsonFailed (Rec Identity out)+interpretLorentzInstr env (compileLorentz -> instr) inp =+  fromValStack <$> interpretInstr env instr (toValStack inp)++-- | Like 'interpretLorentzInstr', but works on lambda rather than+-- arbitrary instruction.+interpretLorentzLambda+  :: (IsoValue inp, IsoValue out)+  => ContractEnv+  -> Lambda inp out+  -> inp+  -> Either MichelsonFailed out+interpretLorentzLambda env instr inp = do+  res <- interpretLorentzInstr env instr (Identity inp :& RNil)+  let Identity out :& RNil = res+  return out++-- | Lorentz version of analyzer.+analyzeLorentz :: inp :-> out -> AnalyzerRes+analyzeLorentz = analyze . compileLorentz
src/Lorentz/Store.hs view
@@ -24,6 +24,7 @@  -} module Lorentz.Store+  {-# DEPRECATED "Contract storage can contain multiple big_maps starting from Michelson 005" #-}   ( -- * Store and related type definitions     Store (..)   , type (|->)@@ -35,6 +36,7 @@     -- ** Instructions   , storeMem   , storeGet+  , storeUpdate   , storeInsert   , storeInsertNew   , storeDelete@@ -42,6 +44,7 @@     -- ** Instruction constraints   , StoreMemC   , StoreGetC+  , StoreUpdateC   , StoreInsertC   , StoreDeleteC   , HasStore@@ -59,6 +62,7 @@      -- * Store management from Haskell   , storePiece+  , storeKeyValueList   , storeLookup      -- ** Function constraints@@ -69,27 +73,26 @@ import Data.Default (Default) import qualified Data.Kind as Kind import qualified Data.Map as Map-import Data.Singletons (SingI) import Data.Type.Bool (If, type (||)) import Data.Type.Equality (type (==)) import Data.Vinyl.Derived (Label) import GHC.Generics ((:+:)) import qualified GHC.Generics as G import GHC.TypeLits (AppendSymbol, ErrorMessage(..), KnownSymbol, Symbol, TypeError)-import GHC.TypeNats (type (+))+import GHC.TypeNats (type (+), Nat) import Type.Reflection ((:~:)(Refl))  import Lorentz.ADT import Lorentz.Base import Lorentz.Coercions import Lorentz.Constraints-import Lorentz.Instr+import Lorentz.Instr as L import Lorentz.Macro-import Michelson.Interpret.Pack+import Lorentz.Pack+import Lorentz.StoreClass import Michelson.Typed.Haskell.Instr.Sum import Michelson.Typed.Haskell.Value import Michelson.Typed.Instr-import Michelson.Typed.Scope  {-# ANN module ("HLint: ignore Use 'natVal' from Universum" :: Text) #-} @@ -231,16 +234,23 @@ type GetStoreValue store name = MSValue (GetStore name store)  packKey-  :: forall (idx :: CtorIdx) t s.-     (KnownNat idx, Typeable t, SingI t, HasNoOp t, HasNoBigMap t)-  => Instr (t : s) (ToT ByteString : s)+  :: forall (idx :: CtorIdx) a s.+     (KnownNat idx, NicePackedValue a)+  => (a : s) :-> (ByteString : s) packKey =-  PUSH (toVal . natVal $ Proxy @idx) `Seq`-  PAIR @(ToT Natural) @t `Seq`-  PACK+  withDict (nicePackedValueEvi @a) $+    push (natVal $ Proxy @idx) #+    pair @Natural @a #+    pack +wrapBigMapImage :: (v : s) :-> ((k |-> v) : s)+wrapBigMapImage = coerce_++unwrapBigMapImage :: ((k |-> v) : s) :-> (v : s)+unwrapBigMapImage = coerce_+ type StoreOpC store name =-  ( Each [Typeable, SingI, HasNoOp, HasNoBigMap] '[ToT (MSKey (GetStore name store))]+  ( NicePackedValue (MSKey (GetStore name store))   , KnownNat (MSCtorIdx (GetStore name store))   ) @@ -255,9 +265,9 @@      (StoreMemC store name)   => Label name   -> GetStoreKey store name : Store store : s :-> Bool : s-storeMem _ = I $-  packKey @(MSCtorIdx (GetStore name store)) `Seq`-  MEM+storeMem _ =+  packKey @(MSCtorIdx (GetStore name store)) #+  I MEM  type StoreMemC store name = StoreOpC store name @@ -267,19 +277,41 @@   => Label name   -> GetStoreKey store name : Store store : s        :-> Maybe (GetStoreValue store name) : s-storeGet label = I $-  packKey @(MSCtorIdx (GetStore name store)) `Seq`-  GET `Seq`-  IF_NONE (NONE) (instrUnwrapUnsafe @store label `Seq` SOME)+storeGet label =+  packKey @(MSCtorIdx (GetStore name store)) #+  I GET #+  ifNone none (unwrapUnsafe_ @store label # unwrapBigMapImage # L.some)  type StoreGetC store name =   ( StoreOpC store name   , InstrUnwrapC store name-  , SingI (ToT (GetStoreValue store name))+  , KnownValue (GetStoreValue store name)   , CtorHasOnlyField name store       (GetStoreKey store name |-> GetStoreValue store name)   ) +storeUpdate+  :: forall store name s.+     StoreUpdateC store name+  => Label name+  -> GetStoreKey store name+      : Maybe (GetStoreValue store name)+      : Store store+      : s+  :-> Store store : s+storeUpdate label =+  packKey @(MSCtorIdx (GetStore name store)) #+  dip (ifNone none (wrapBigMapImage # wrap_ @store label # L.some)) #+  I UPDATE++type StoreUpdateC store name =+  ( KnownValue store+  , StoreOpC store name+  , InstrWrapC store name+  , CtorHasOnlyField name store+      (GetStoreKey store name |-> GetStoreValue store name)+  )+ storeInsert   :: forall store name s.      StoreInsertC store name@@ -289,10 +321,10 @@       : Store store       : s   :-> Store store : s-storeInsert label = I $-  packKey @(MSCtorIdx (GetStore name store)) `Seq`-  DIP (instrWrap @store label `Seq` SOME) `Seq`-  UPDATE+storeInsert label =+  packKey @(MSCtorIdx (GetStore name store)) #+  dip (wrapBigMapImage # wrap_ @store label # L.some) #+  I UPDATE  type StoreInsertC store name =   ( StoreOpC store name@@ -303,18 +335,18 @@  -- | Insert a key-value pair, but fail if it will overwrite some existing entry. storeInsertNew-  :: forall store name err s.-     (StoreInsertC store name, KnownSymbol name, KnownValue err)+  :: forall store name s.+     (StoreInsertC store name, KnownSymbol name)   => Label name-  -> (forall s0. GetStoreKey store name : s0 :-> err : s0)+  -> (forall s0 any. GetStoreKey store name : s0 :-> any)   -> GetStoreKey store name       : GetStoreValue store name       : Store store       : s   :-> Store store : s-storeInsertNew label mkErr =+storeInsertNew label doFail =   duupX @3 # duupX @2 # storeMem label #-  if_ (mkErr # failWith)+  if_ doFail       (storeInsert label)  storeDelete@@ -324,14 +356,14 @@   => Label name   -> GetStoreKey store name : Store store : s      :-> Store store : s-storeDelete _ = I $-  packKey @(MSCtorIdx (GetStore name store)) `Seq`-  DIP (NONE @(ToT store)) `Seq`-  UPDATE+storeDelete _ =+  packKey @(MSCtorIdx (GetStore name store)) #+  dip (none @store) #+  I UPDATE  type StoreDeleteC store name =   ( StoreOpC store name-  , SingI (ToT store)+  , KnownValue store   )  -- | This constraint can be used if a function needs to work with@@ -367,6 +399,22 @@   GForAllHasStore _ (G.C1 _ _) = ()   GForAllHasStore _ G.V1 = () +-- Instances+----------------------------------------------------------------------------++instance ( StoreMemC store name, StoreGetC store name+         , StoreUpdateC store name+         , key ~ GetStoreKey store name, value ~ GetStoreValue store name+         ) =>+         StoreHasSubmap (Store store) name key value where+  storeSubmapOps = StoreSubmapOps+    { sopMem = storeMem+    , sopGet = storeGet+    , sopUpdate = storeUpdate+    , sopDelete = Just storeDelete+    , sopInsert = Just storeInsert+    }+ -- Examples ---------------------------------------------------------------------------- @@ -503,18 +551,18 @@  -- | Insert a key-value pair, but fail if it will overwrite some existing entry. storageInsertNew-  :: forall store name fields err s.-     (StoreInsertC store name, KnownSymbol name, KnownValue err)+  :: forall store name fields s.+     (StoreInsertC store name, KnownSymbol name)   => Label name-  -> (forall s0. GetStoreKey store name : s0 :-> err : s0)+  -> (forall s0 any. GetStoreKey store name : s0 :-> any)   -> GetStoreKey store name       : GetStoreValue store name       : StorageSkeleton store fields       : s   :-> StorageSkeleton store fields : s-storageInsertNew label mkErr =+storageInsertNew label doFail =   dip (dip (storageUnpack # dup # car # dip cdr)) #-  storeInsertNew label mkErr #+  storeInsertNew label doFail #   pair # storagePack  storageDelete@@ -529,6 +577,21 @@   storeDelete label #   pair # storagePack +-- Instances+----------------------------------------------------------------------------++instance (StoreHasField other fname ftype, IsoValue store, IsoValue other) =>+         StoreHasField (StorageSkeleton store other) fname ftype where+  storeFieldOps = storeFieldOpsDeeper #sFields++instance ( StoreMemC store name, StoreGetC store name+         , StoreUpdateC store name+         , key ~ GetStoreKey store name, value ~ GetStoreValue store name+         , IsoValue other+         ) =>+         StoreHasSubmap (StorageSkeleton store other) name key value where+  storeSubmapOps = storeSubmapOpsDeeper #sMap+ -- Examples ---------------------------------------------------------------------------- @@ -548,12 +611,10 @@  packHsKey   :: forall ctorIdx key.-     ( IsoValue key, KnownValue key, HasNoOp (ToT key), HasNoBigMap (ToT key)-     , KnownNat ctorIdx-     )+     (NicePackedValue key, KnownNat ctorIdx)   => key -> ByteString packHsKey key =-  packValue' $ toVal (natVal (Proxy @ctorIdx), key)+  lPackValue (natVal (Proxy @ctorIdx), key)  -- | Lift a key-value pair to 'Store'. --@@ -571,10 +632,23 @@     , hsWrap @store label (BigMapImage val)     ) +storeKeyValueList+  :: forall name store key value.+     StorePieceC store name key value+  => Label name+  -> [(key, value)]+  -> Store store+storeKeyValueList label keyValues =+  Store . BigMap . Map.fromList $+  Prelude.map (\(key, val) ->+                 ( packHsKey @(MSCtorIdx (GetStore name store)) key+                 , hsWrap @store label (BigMapImage val)+                 )) keyValues+ type StorePieceC store name key value =   ( key ~ GetStoreKey store name   , value ~ GetStoreValue store name-  , IsoValue key, KnownValue key, HasNoOp (ToT key), HasNoBigMap (ToT key)+  , NicePackedValue key   , KnownNat (MSCtorIdx (GetStore name store))   , InstrWrapC store name, Generic store   , ExtractCtorField (GetCtorField store name) ~ (key |-> value)@@ -589,7 +663,7 @@      ( key ~ GetStoreKey store name      , value ~ GetStoreValue store name      , ctorIdx ~ MSCtorIdx (GetStore name store)-     , IsoValue key, KnownValue key, HasNoOp (ToT key), HasNoBigMap (ToT key)+     , NicePackedValue key      , KnownNat ctorIdx      , InstrUnwrapC store name, Generic store      , CtorOnlyField name store ~ (key |-> value)
+ src/Lorentz/StoreClass.hs view
@@ -0,0 +1,351 @@+{-# LANGUAGE FunctionalDependencies #-}++-- | This module provides storage interfaces.+module Lorentz.StoreClass+  ( -- * Class+    StoreHasField (..)+  , StoreFieldOps (..)+  , StoreHasSubmap (..)+  , StoreSubmapOps (..)++    -- * Expressing constraints on storage+  , type (~>)+  , StorageContains++    -- * Methods to work with storage+  , stToField+  , stGetField+  , stSetField+  , stMem+  , stGet+  , stUpdate+  , stDelete+  , stInsert+  , stInsertNew++    -- * Implementations+  , storeFieldOpsADT+  , storeFieldOpsDeeper+  , storeSubmapOpsDeeper+  , storeFieldOpsReferTo+  , storeSubmapOpsReferTo+  , composeStoreFieldOps+  , composeStoreSubmapOps+  ) where++import Data.Vinyl.Derived (Label)++import Lorentz.ADT+import Lorentz.Base+import Lorentz.Constraints+import qualified Lorentz.Instr as L+import qualified Lorentz.Macro as L+import Lorentz.Value+import Michelson.Typed.Haskell++----------------------------------------------------------------------------+-- Fields+----------------------------------------------------------------------------++-- | Datatype containing the full implementation of 'StoreHasField' typeclass.+--+-- We use this grouping because in most cases implementation will be chosen+-- among the default ones, and initializing all methods at once is simpler+-- and more consistent.+-- (One can say that we are trying to emulate benefits of @DerivingVia@ extension.)+data StoreFieldOps store fname ftype = StoreFieldOps+  { sopToField+      :: forall s.+         Label fname -> store : s :-> ftype : s+  , sopSetField+      :: forall s.+         Label fname -> ftype : store : s :-> store : s+  }++-- Using fundeps here for the sake of less amount of boilerplate on user side,+-- switch to type families if having any issues with that.+-- | Provides operations on fields for storage.+class StoreHasField store fname ftype | store fname -> ftype where+  storeFieldOps :: StoreFieldOps store fname ftype++-- | Pick storage field.+stToField+  :: StoreHasField store fname ftype+  => Label fname -> store : s :-> ftype : s+stToField = sopToField storeFieldOps++-- | Get storage field, preserving the storage itself on stack.+stGetField+  :: StoreHasField store fname ftype+  => Label fname -> store : s :-> ftype : store : s+stGetField l = L.dup # sopToField storeFieldOps l++-- | Update storage field.+stSetField+  :: StoreHasField store fname ftype+  => Label fname -> ftype : store : s :-> store : s+stSetField = sopSetField storeFieldOps++----------------------------------------------------------------------------+-- Virtual big maps+----------------------------------------------------------------------------++-- | Datatype containing the full implementation of 'StoreHasField' typeclass.+--+-- We use this grouping because in most cases implementation will be chosen+-- among the default ones, and initializing all methods at once is simpler+-- and more consistent.+-- (One can say that we are trying to emulate @DerivingVia@ extension.)+data StoreSubmapOps store mname key value = StoreSubmapOps+  { sopMem+      :: forall s.+         Label mname -> key : store : s :-> Bool : s+  , sopGet+      :: forall s.+         Label mname -> key : store : s :-> Maybe value : s+  , sopUpdate+      :: forall s.+         Label mname -> key : Maybe value : store : s :-> store : s++    -- Methods below are derivatives of methods above, they can be provided+    -- if for given specific storage type more efficient implementation is+    -- available.+  , sopDelete+      :: forall s.+         Maybe (Label mname -> key : store : s :-> store : s)+  , sopInsert+      :: forall s.+         Maybe (Label mname -> key : value : store : s :-> store : s)+  }++-- | Provides operations on fields for storage.+class StoreHasSubmap store mname key value | store mname -> key value where+  storeSubmapOps :: StoreSubmapOps store mname key value++-- | Check value presence in storage.+stMem+  :: StoreHasSubmap store mname key value+  => Label mname -> key : store : s :-> Bool : s+stMem = sopMem storeSubmapOps++-- | Get value in storage.+stGet+  :: StoreHasSubmap store mname key value+  => Label mname -> key : store : s :-> Maybe value : s+stGet = sopGet storeSubmapOps++-- | Update a value in storage.+stUpdate+  :: StoreHasSubmap store mname key value+  => Label mname -> key : Maybe value : store : s :-> store : s+stUpdate = sopUpdate storeSubmapOps++-- | Delete a value in storage.+stDelete+  :: forall store mname key value s.+     (StoreHasSubmap store mname key value, KnownValue value)+  => Label mname -> key : store : s :-> store : s+stDelete l = case sopDelete storeSubmapOps of+  Just delOp -> delOp l+  Nothing -> L.dip L.none # stUpdate l++-- | Add a value in storage.+stInsert+  :: StoreHasSubmap store mname key value+  => Label mname -> key : value : store : s :-> store : s+stInsert l = case sopInsert storeSubmapOps of+  Just insOp -> insOp l+  Nothing -> L.dip L.some # stUpdate l++-- | Add a value in storage, but fail if it will overwrite some existing entry.+stInsertNew+  :: StoreHasSubmap store mname key value+  => Label mname+  -> (forall s0 any. key : s0 :-> any)+  -> key : value : store : s+  :-> store : s+stInsertNew l doFail =+  L.duupX @3 # L.duupX @2 # stMem l #+  L.if_ doFail (stInsert l)++-- Instances+----------------------------------------------------------------------------++-- | 'BigMap' can be used as standalone key-value storage,+-- name of submap is not accounted in this case.+instance (key ~ key', value ~ value', IsComparable key) =>+         StoreHasSubmap (BigMap key' value') name key value where+  storeSubmapOps = StoreSubmapOps+    { sopMem = \_label -> L.mem+    , sopGet = \_label -> L.get+    , sopUpdate = \_label -> L.update+    , sopDelete = Nothing+    , sopInsert = Nothing+    }++-- | 'Map' can be used as standalone key-value storage if very needed.+instance (key ~ key', value ~ value', IsComparable key) =>+         StoreHasSubmap (Map key' value') name key value where+  storeSubmapOps = StoreSubmapOps+    { sopMem = \_label -> L.mem+    , sopGet = \_label -> L.get+    , sopUpdate = \_label -> L.update+    , sopDelete = Nothing+    , sopInsert = Nothing+    }+++-- Implementations+----------------------------------------------------------------------------++-- | Implementation of 'StoreHasField' for case of datatype+-- keeping a pack of fields.+storeFieldOpsADT+  :: HasFieldOfType dt fname ftype+  => StoreFieldOps dt fname ftype+storeFieldOpsADT = StoreFieldOps+  { sopToField = toField+  , sopSetField = setField+  }++-- | Implementation of 'StoreHasField' for a data type which has an+-- instance of 'StoreHasField' inside.+-- For instance, it can be used for top-level storage.+storeFieldOpsDeeper+  :: ( HasFieldOfType storage fieldsPartName fields+     , StoreHasField fields fname ftype+     )+  => Label fieldsPartName+  -> StoreFieldOps storage fname ftype+storeFieldOpsDeeper fieldsLabel =+  composeStoreFieldOps fieldsLabel storeFieldOpsADT storeFieldOps++-- | Implementation of 'StoreHasSubmap' for a data type which has an+-- instance of 'StoreHasSubmap' inside.+-- For instance, it can be used for top-level storage.+storeSubmapOpsDeeper+  :: ( HasFieldOfType storage bigMapPartName fields+     , StoreHasSubmap fields mname key value+     )+  => Label bigMapPartName+  -> StoreSubmapOps storage mname key value+storeSubmapOpsDeeper submapLabel =+  composeStoreSubmapOps submapLabel storeFieldOpsADT storeSubmapOps++{- | Pretend that given 'StoreSubmapOps' implementation is made up+for submap with name @desiredName@, not its actual name.+Logic of the implementation remains the same.++Use case: imagine that your code requires access to submap named @X@,+but in your storage that submap is called @Y@.+Then you implement the instance which makes @X@ refer to @Y@:++@+instance StoreHasSubmap Store X Key Value where+  storeSubmapOps = storeSubmapOpsReferTo #Y storeSubmapOpsForY+@+-}+storeSubmapOpsReferTo+  :: Label name+  -> StoreSubmapOps storage name key value+  -> StoreSubmapOps storage desiredName key value+storeSubmapOpsReferTo l StoreSubmapOps{..} =+  StoreSubmapOps+  { sopMem = \_l -> sopMem l+  , sopGet = \_l -> sopGet l+  , sopUpdate = \_l -> sopUpdate l+  , sopDelete = (\op _l -> op l) <$> sopDelete+  , sopInsert = (\op _l -> op l) <$> sopInsert+  }++-- | Pretend that given 'StoreSubmapOps' implementation is made up+-- for submap with name @desiredName@, not its actual name.+-- Logic of the implementation remains the same.+--+-- See also 'storeSubmapOpsReferTo'.+storeFieldOpsReferTo+  :: Label name+  -> StoreFieldOps storage name field+  -> StoreFieldOps storage desiredName field+storeFieldOpsReferTo l StoreFieldOps{..} =+  StoreFieldOps+  { sopToField = \_l -> sopToField l+  , sopSetField = \_l -> sopSetField l+  }++-- | Chain two implementations of field operations.+--+-- Suits for a case when your store does not contain its fields directly+-- rather has a nested structure.+composeStoreFieldOps+  :: Label nameInStore+  -> StoreFieldOps store nameInStore substore+  -> StoreFieldOps substore nameInSubstore field+  -> StoreFieldOps store nameInSubstore field+composeStoreFieldOps l1 ops1 ops2 =+  StoreFieldOps+  { sopToField = \l2 ->+      sopToField ops1 l1 # sopToField ops2 l2+  , sopSetField = \l2 ->+      L.dip (L.dup # sopToField ops1 l1) #+      sopSetField ops2 l2 #+      sopSetField ops1 l1+  }++-- | Chain implementations of field and submap operations.+composeStoreSubmapOps+  :: Label nameInStore+  -> StoreFieldOps store nameInStore substore+  -> StoreSubmapOps substore mname key value+  -> StoreSubmapOps store mname key value+composeStoreSubmapOps l1 ops1 ops2 =+  StoreSubmapOps+  { sopMem = \l2 ->+      L.dip (sopToField ops1 l1) # sopMem ops2 l2+  , sopGet = \l2 ->+      L.dip (sopToField ops1 l1) # sopGet ops2 l2+  , sopUpdate = \l2 ->+      L.dip (L.dip (L.dup # sopToField ops1 l1)) #+      sopUpdate ops2 l2 #+      sopSetField ops1 l1+  , sopDelete = case sopDelete ops2 of+      Nothing -> Nothing+      Just delOp -> Just $ \l2 ->+        L.dip (L.dup # sopToField ops1 l1) #+        delOp l2 #+        sopSetField ops1 l1+  , sopInsert = case sopInsert ops2 of+      Nothing -> Nothing+      Just insOp -> Just $ \l2 ->+        L.dip (L.dip (L.dup # sopToField ops1 l1)) #+        insOp l2 #+        sopSetField ops1 l1+  }++----------------------------------------------------------------------------+-- Utilities+----------------------------------------------------------------------------++-- | Indicates a submap with given key and value types.+data k ~> v+infix 9 ~>++{- | Concise way to write down constraints with expected content of a storage.++Use it like follows:++@+type StorageConstraint = StorageContains+  [ "fieldInt" := Int+  , "fieldNat" := Nat+  , "balances" := Address ~> Int+  ]+@++-}+type family StorageContains store (content :: [NamedField]) :: Constraint where+  StorageContains _ '[] = ()+  StorageContains store ((n := k ~> v) ': ct) =+    (StoreHasSubmap store n k v, StorageContains store ct)+  StorageContains store ((n := ty) ': ct) =+    (StoreHasField store n ty, StorageContains store ct)
src/Lorentz/Test.hs view
@@ -28,18 +28,30 @@   , validate   , setMaxSteps   , setNow+  , rewindTime   , withSender+  , setChainId+  , branchout+  , (?-)+  , offshoot    -- ** Validators   , composeValidators   , composeValidatorsList   , expectAnySuccess+  , expectNoUpdates+  , expectNoStorageUpdates   , lExpectStorageUpdate   , lExpectBalance   , lExpectStorageConst   , lExpectMichelsonFailed   , lExpectFailWith-  , lExpectUserError+  , lExpectError+  , lExpectErrorNumeric+  , lExpectCustomError+  , lExpectCustomErrorNumeric+  , lExpectCustomError_+  , lExpectCustomErrorNumeric_   , lExpectConsumerStorage   , lExpectViewConsumerStorage @@ -67,6 +79,9 @@   , minTimestamp   , maxTimestamp   , midTimestamp++  -- * Special contracts for testing+  , contractConsumer   ) where  import Michelson.Test.Dummy@@ -75,4 +90,5 @@ import Michelson.Test.Unit import Michelson.Test.Util +import Lorentz.Test.Consumer import Lorentz.Test.Integrational as Exports
+ src/Lorentz/Test/Consumer.hs view
@@ -0,0 +1,14 @@+-- | Contract which remembers all parameters it has been called with.+--+-- Useful to save return values of @View@ entry points.+module Lorentz.Test.Consumer+  ( contractConsumer+  ) where++import Lorentz.Base+import Lorentz.Instr+import Lorentz.Macro++-- | Remembers parameters it was called with, last goes first.+contractConsumer :: Contract cp [cp]+contractConsumer = unpair # cons # nil # pair
src/Lorentz/Test/Integrational.hs view
@@ -13,6 +13,11 @@   , genesisAddress5   , genesisAddress6 +    -- * Testing engine for bare Typed primitives+  , tOriginate+  , tTransfer+  , tExpectStorageConst+     -- * Testing engine   , I.IntegrationalValidator   , SuccessValidator@@ -28,37 +33,56 @@   , I.validate   , I.setMaxSteps   , I.setNow+  , I.rewindTime   , I.withSender+  , I.setChainId+  , I.branchout+  , (I.?-)+  , I.offshoot    -- * Validators   , I.composeValidators   , I.composeValidatorsList   , I.expectAnySuccess+  , I.expectNoUpdates+  , I.expectNoStorageUpdates   , lExpectStorageUpdate   , lExpectBalance   , lExpectStorageConst+  -- * Errors   , lExpectMichelsonFailed   , lExpectFailWith-  , lExpectUserError+  , lExpectError+  , lExpectErrorNumeric+  , lExpectCustomError+  , lExpectCustomErrorNumeric+  , lExpectCustomError_+  , lExpectCustomErrorNumeric_++  -- ** Consumer   , lExpectConsumerStorage   , lExpectViewConsumerStorage   ) where  import Data.Default (Default(..))-import Data.Singletons (SingI(..))+import Data.Singletons (SingI) import Data.Typeable (gcast)+import Data.Vinyl.Derived (Label) import Fmt (Buildable, listF, (+|), (|+)) import Named ((:!), arg)  import qualified Lorentz as L-import Michelson.Interpret (InterpretUntypedError(..), MichelsonFailed(..))+import Lorentz.Constraints+import Lorentz.Run+import Lorentz.Value+import Michelson.Interpret (InterpretError(..), MichelsonFailed(..)) import Michelson.Runtime import Michelson.Runtime.GState import Michelson.Test.Integrational (IntegrationalScenarioM, SuccessValidator) import qualified Michelson.Test.Integrational as I import Michelson.TypeCheck (typeVerifyValue) import qualified Michelson.Typed as T-import Tezos.Address+import Michelson.Typed.Scope import Tezos.Core import Util.Named ((.!)) @@ -74,38 +98,38 @@  -- | Like 'originate', but for typed contract and value. tOriginate-  :: (SingI cp, SingI st, T.HasNoOp st)+  :: (ParameterScope cp, StorageScope st)   => T.Contract cp st -> Text -> T.Value st -> Mutez -> IntegrationalScenarioM Address tOriginate contract name value balance =   I.originate (T.convertContract contract) name (T.untypeValue value) balance  -- | Like 'originate', but for Lorentz contracts. lOriginate-  :: ( SingI (T.ToT cp), SingI (T.ToT st), T.HasNoOp (T.ToT st)-     , T.IsoValue st-     )+  :: forall cp st.+     (NiceParameter cp, NiceStorage st)   => L.Contract cp st   -> Text   -> st   -> Mutez-  -> IntegrationalScenarioM (T.ContractAddr cp)+  -> IntegrationalScenarioM (ContractRef cp) lOriginate contract name value balance =-  T.ContractAddr <$>-  tOriginate (L.compileLorentz contract) name (T.toVal value) balance+  withDict (niceParameterEvi @cp) $+  withDict (niceStorageEvi @st) $ do+    addr <- tOriginate (compileLorentz contract) name (T.toVal value) balance+    return (L.ContractRef addr def)  -- | Originate a contract with empty balance and default storage. lOriginateEmpty-  :: ( SingI (T.ToT cp), SingI (T.ToT st), T.HasNoOp (T.ToT st)-     , T.IsoValue st, Default st-     )+  :: (NiceParameter cp, NiceStorage st, Default st)   => L.Contract cp st   -> Text-  -> IntegrationalScenarioM (T.ContractAddr cp)+  -> IntegrationalScenarioM (ContractRef cp) lOriginateEmpty contract name = lOriginate contract name def (unsafeMkMutez 0)  -- | Similar to 'transfer', for typed values. tTransfer-  :: (SingI cp, T.HasNoOp cp)+  :: forall cp.+     (ParameterScope cp)   => "from" :! Address   -> "to" :! Address   -> Mutez@@ -114,41 +138,47 @@ tTransfer (arg #from -> from) (arg #to -> to) money param =   let txData = TxData         { tdSenderAddress = from-        , tdParameter = T.untypeValue param+        , tdParameter =+            withDict (properParameterEvi @cp) $+            T.untypeValue param         , tdAmount = money         }   in I.transfer txData to  -- | Similar to 'transfer', for Lorentz values. lTransfer-  :: (SingI (T.ToT cp), T.HasNoOp (T.ToT cp), T.IsoValue cp)+  :: forall cp contract.+     (NiceParameter cp, ToContractRef cp contract)   => "from" :! Address-  -> "to" :! T.ContractAddr cp+  -> "to" :! contract   -> Mutez   -> cp   -> IntegrationalScenarioM ()-lTransfer from (arg #to -> T.ContractAddr to) money param =-  tTransfer from (#to .! to) money (T.toVal param)+lTransfer from (convertContractRef @cp @Address . arg #to -> to) money param =+  withDict (niceParameterEvi @cp) $+    tTransfer from (#to .! to) money (T.toVal param) --- | Call a contract without caring about source address and money.+-- | Call a contract without caring about the source address. Transfers 0 mutez. lCall-  :: (SingI (T.ToT cp), T.HasNoOp (T.ToT cp), T.IsoValue cp)-  => T.ContractAddr cp -> cp -> IntegrationalScenarioM ()+  :: forall cp contract.+     (NiceParameter cp, ToContractRef cp contract)+  => contract -> cp -> IntegrationalScenarioM () lCall contract param =   lTransfer (#from .! genesisAddress) (#to .! contract)-    (unsafeMkMutez 1000) param+    (unsafeMkMutez 0) param  ---------------------------------------------------------------------------- -- Validators to be used within 'IntegrationalValidator' ---------------------------------------------------------------------------- +-- Expect something successful+ -- | Similar to 'expectStorageUpdate', for Lorentz values. lExpectStorageUpdate-  :: ( T.IsoValue st, Each [Typeable, SingI, T.HasNoOp] '[T.ToT st]-     , HasCallStack-     )-  => T.ContractAddr cp -> (st -> Either I.ValidationError ()) -> SuccessValidator-lExpectStorageUpdate (T.ContractAddr addr) predicate =+  :: forall st addr.+     (NiceStorage st, ToAddress addr, HasCallStack)+  => addr -> (st -> Either I.ValidationError ()) -> SuccessValidator+lExpectStorageUpdate (toAddress -> addr) predicate =   I.expectStorageUpdate addr $ \got -> do     val <- first I.UnexpectedTypeCheckError $ typeCheck got     predicate $ T.fromVal val@@ -160,21 +190,34 @@     initSt = error "Typechecker state unavailable"  -- | Like 'expectBalance', for Lorentz values.-lExpectBalance :: T.ContractAddr cp -> Mutez -> SuccessValidator-lExpectBalance (T.ContractAddr addr) money = I.expectBalance addr money+lExpectBalance :: ToAddress addr => addr -> Mutez -> SuccessValidator+lExpectBalance (toAddress -> addr) money = I.expectBalance addr money +-- | Similar to 'expectStorageConst', for typed stuff.+tExpectStorageConst+  :: forall st.+     (StorageScope st)+  => Address -> Value st -> SuccessValidator+tExpectStorageConst addr expected =+  I.expectStorageConst addr (T.untypeValue expected)+ -- | Similar to 'expectStorageConst', for Lorentz values. lExpectStorageConst-  :: (T.IsoValue st, Each '[SingI, T.HasNoOp] '[T.ToT st])-  => T.ContractAddr cp -> st -> SuccessValidator-lExpectStorageConst (T.ContractAddr addr) expected =-  I.expectStorageConst addr (T.untypeValue $ T.toVal expected)+  :: forall st addr.+     (NiceStorage st, ToAddress addr)+  => addr -> st -> SuccessValidator+lExpectStorageConst (toAddress -> addr) expected =+  withDict (niceStorageEvi @st) $+    tExpectStorageConst addr (T.toVal expected) +-- Expect errors+ -- | Expect that interpretation of contract with given address ended -- with [FAILED]. lExpectMichelsonFailed-  :: (MichelsonFailed -> Bool) -> T.ContractAddr cp -> InterpreterError -> Bool-lExpectMichelsonFailed predicate (T.ContractAddr addr) =+  :: forall addr. (ToAddress addr)+  => (MichelsonFailed -> Bool) -> addr -> InterpreterError -> Bool+lExpectMichelsonFailed predicate (toAddress -> addr) =   I.expectMichelsonFailed predicate addr  -- | Expect contract to fail with "FAILWITH" instruction and provided value@@ -191,19 +234,80 @@           Nothing -> False     _ -> False --- | Expect contract to fail with given 'LorentzUserError' error.-lExpectUserError+-- | Expect contract to fail with given error.+lExpectError   :: forall e.-      (Typeable (T.ToT e), T.IsoValue e)+      (L.IsError e)   => (e -> Bool) -> InterpreterError -> Bool-lExpectUserError predicate = lExpectFailWith (predicate . L.unLorentzUserError)+lExpectError = lExpectError' L.errorFromVal +-- | Version of 'lExpectError' for the case when numeric+-- representation of errors is used.+lExpectErrorNumeric+  :: forall e.+      (L.IsError e)+  => L.ErrorTagMap -> (e -> Bool) -> InterpreterError -> Bool+lExpectErrorNumeric errorTagMap =+  lExpectError' (L.errorFromValNumeric errorTagMap)++lExpectError' ::+     forall e.+     (forall t. (Typeable t, SingI t) =>+                  Value t -> Either Text e)+  -> (e -> Bool)+  -> InterpreterError+  -> Bool+lExpectError' errorFromValImpl predicate =+  \case+    IEInterpreterFailed _ (RuntimeFailure (MichelsonFailedWith err, _)) ->+        case errorFromValImpl err of+          Right err' -> predicate err'+          Left _ -> False+    _ -> False++-- | Expect contract to fail with given 'CustomError'.+lExpectCustomError+  :: forall tag arg.+      (L.IsError (L.CustomError tag), arg ~ L.ErrorArg tag, Eq arg)+  => Label tag -> arg -> InterpreterError -> Bool+lExpectCustomError l a =+  lExpectError (== L.CustomError l a)++-- | Version of 'lExpectCustomError' for the case when numeric+-- representation of errors is used.+lExpectCustomErrorNumeric+  :: forall tag arg.+      (L.IsError (L.CustomError tag), arg ~ L.ErrorArg tag, Eq arg)+  => L.ErrorTagMap -> Label tag -> arg -> InterpreterError -> Bool+lExpectCustomErrorNumeric errorTagMap l a =+  lExpectErrorNumeric errorTagMap (== L.CustomError l a)++-- | Specialization of 'lExpectCustomError' for non-arg error case.+lExpectCustomError_+  :: forall tag.+      (L.IsError (L.CustomError tag), L.ErrorArg tag ~ ())+  => Label tag -> InterpreterError -> Bool+lExpectCustomError_ l =+  lExpectCustomError l ()++-- | Version of 'lExpectCustomError_' for the case when numeric+-- representation of errors is used.+lExpectCustomErrorNumeric_+  :: forall tag.+      (L.IsError (L.CustomError tag), L.ErrorArg tag ~ ())+  => L.ErrorTagMap -> Label tag -> InterpreterError -> Bool+lExpectCustomErrorNumeric_ errorTagMap l =+  lExpectCustomErrorNumeric errorTagMap l ()++-- Consumer+ -- | Version of 'lExpectStorageUpdate' specialized to "consumer" contract -- (see 'Lorentz.Contracts.Consumer.contractConsumer'). lExpectConsumerStorage-  :: (st ~ [cp], T.IsoValue st, Each [Typeable, SingI, T.HasNoOp] '[T.ToT st])-  => T.ContractAddr cp -> (st -> Either I.ValidationError ()) -> SuccessValidator-lExpectConsumerStorage = lExpectStorageUpdate+  :: forall cp st contract.+     (st ~ [cp], NiceStorage st, ToContractRef cp contract)+  => contract -> (st -> Either I.ValidationError ()) -> SuccessValidator+lExpectConsumerStorage = lExpectStorageUpdate . toContractRef @cp  -- | Assuming that "consumer" contract receives a value from 'View', expect -- this view return value to be the given one.@@ -212,18 +316,16 @@ -- this function cares about it, so you should provide a list of expected values -- in the same order in which the corresponding events were happenning. lExpectViewConsumerStorage-  :: ( st ~ [cp], cp ~ (arg, Maybe res)-     , Eq res, Buildable res-     , T.IsoValue st, Each [Typeable, SingI, T.HasNoOp] '[T.ToT st]+  :: ( st ~ [cp]+     , Eq cp, Buildable cp+     , NiceStorage st+     , ToContractRef cp contract      )-  => T.ContractAddr cp -> [res] -> SuccessValidator+  => contract -> [cp] -> SuccessValidator lExpectViewConsumerStorage addr expected =-  lExpectConsumerStorage addr (extractJusts >=> matchExpected . reverse)+  lExpectConsumerStorage addr (matchExpected . reverse)   where-    extractJusts = mapM $ \case-      (_, Just got) -> pure got-      (_, Nothing) -> mkError "Consumer got empty value unexpectedly"-    mkError = Left . I.CustomError+    mkError = Left . I.CustomValidationError     matchExpected got       | got == expected = pass       | otherwise = mkError $ "Expected " +| listF expected |+
+ src/Lorentz/TestScenario.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE DerivingStrategies, DeriveAnyClass #-}++module Lorentz.TestScenario+  ( TestScenario+  , showTestScenario+  ) where++import Fmt (Buildable, Builder, fmt, (+|), (|+))++import Lorentz.Constraints (KnownValue, NicePrintedValue, NoOperation)+import Lorentz.Print (printLorentzValue)+import Michelson.Typed.Haskell.Value (IsoValue)+import Tezos.Address (Address)++-- | Type that represents test scenario for Lorentz contract.+-- Simply put, it is sequence of pairs (`sender`, `parameter`).+-- Using this sequence we can perform transfers to the desired contract.+type TestScenario param = [(Address, param)]++-- | Function to get textual representation of @TestScenario@, each Parameter+-- is printed as a raw Michelson value.+-- This representation can later be used in order to run test scenario+-- on real network.+--+-- The format for a single contract call is the following:+-- # `printed Lorentz parameter` (actually comment)+-- `sender address`+-- `printed raw Michelson parameter`+showTestScenario+  :: (Buildable param, NicePrintedValue param)+  => TestScenario param -> Text+showTestScenario = fmt . foldMap formatParam+  where+     formatParam+       :: (Buildable param, KnownValue param, NoOperation param)+       => (Address, param) -> Builder+     formatParam (addr, param) =+       "# " +| param |+ "\n" +|+       addr |+ "\n" +|+       printLorentzValue True param |+ "\n"++data Parameter+  = Param1 Integer Bool+  | Param2+  | Param3 Natural Natural+  deriving stock Generic+  deriving anyclass IsoValue++_mkTestScenarioExample :: Address -> TestScenario Parameter+_mkTestScenarioExample owner =+  [ (owner, Param1 5 False)+  , (owner, Param2)+  , (owner, Param3 2 2)+  ]
+ src/Lorentz/UParam.hs view
@@ -0,0 +1,390 @@+{-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+{-# OPTIONS_GHC -Wno-orphans #-}++module Lorentz.UParam+  ( UParam (..)+  , EntryPointKind+  , type (?:)++    -- * Construction+  , mkUParam++    -- * Deconstruction+  , ConstrainedSome (..)+  , UnpackUParam+  , unpackUParam++    -- * Pattern-matching+  , EntryPointsImpl+  , UParamFallback+  , EntryPointLookupError (..)+  , CaseUParam+  , caseUParam+  , caseUParamT+  , uparamFallbackFail++    -- * Constraints+  , LookupEntryPoint+  , RequireUniqueEntryPoints++    -- * Conversion from ADT+  , uparamFromAdt+  , UParamLinearize+  , UParamLinearized++    -- * Documentation+  , pbsUParam++    -- * Internals used for entrypoint-wise migrations+  , unwrapUParam+  ) where++import Data.Constraint ((\\))+import qualified Data.Kind as Kind+import Data.Vinyl.Core (Rec(..))+import Data.Vinyl.Derived (Label)+import Data.Vinyl.TypeLevel (type (++))+import qualified Fcf+import Fmt (Buildable(..))+import GHC.Generics ((:*:)(..), (:+:)(..))+import qualified GHC.Generics as G+import GHC.TypeLits (KnownSymbol, Symbol)+import qualified Text.Show++import Lorentz.ADT+import Lorentz.Base+import Lorentz.Coercions+import Lorentz.EntryPoints.Doc+import Lorentz.Constraints+import Lorentz.Errors+import Lorentz.Instr as L+import Lorentz.Macro+import Lorentz.Pack+import Michelson.Text+import Michelson.Typed+import Util.Type+import Util.TypeLits+import Util.TypeTuple+import Util.Markdown++-- | An entry point is described by two types: its name and type of argument.+type EntryPointKind = (Symbol, Kind.Type)++-- | A convenient alias for type-level name-something pair.+type (n :: Symbol) ?: (a :: k) = '(n, a)++-- | Encapsulates parameter for one of entry points.+-- It keeps entry point name and corresponding argument serialized.+--+-- In Haskell world, we keep an invariant of that contained value relates+-- to one of entry points from @entries@ list.+newtype UParam (entries :: [EntryPointKind]) = UParamUnsafe (MText, ByteString)+  deriving stock (Generic, Eq, Show)+  deriving anyclass (IsoValue)++----------------------------------------------------------------------------+-- Common type-level stuff+----------------------------------------------------------------------------++-- | Get type of entry point argument by its name.+type family LookupEntryPoint (name :: Symbol) (entries :: [EntryPointKind])+             :: Kind.Type where+  LookupEntryPoint name ('(name, a) ': _) = a+  LookupEntryPoint name (_ ': entries) = LookupEntryPoint name entries+  LookupEntryPoint name '[] =+    TypeError ('Text "Entry point " ':<>: 'ShowType name ':<>:+               'Text " in not in the entry points list")++-- | Ensure that given entry points do no contain duplicated names.+type family RequireUniqueEntryPoints (entries :: [EntryPointKind])+             :: Constraint where+  RequireUniqueEntryPoints entries =+    RequireAllUnique "entry point" (Fcf.Eval (Fcf.Map Fcf.Fst entries))++----------------------------------------------------------------------------+-- Construction+----------------------------------------------------------------------------++-- | Construct a 'UParam' safely.+mkUParam+  :: ( KnownSymbol name, NicePackedValue a+     , LookupEntryPoint name entries ~ a+     , RequireUniqueEntryPoints entries+     )+  => Label name -> a -> UParam entries+mkUParam label (a :: a) =+  UParamUnsafe (labelToMText label, lPackValue a)+    \\ nicePackedValueEvi @a++-- Example+----------------------------------------------------------------------------++type MyEntryPoints =+  [ "add" ?: Integer+  , "reset" ?: ()+  ]++_mkParamSample1 :: UParam MyEntryPoints+_mkParamSample1 = mkUParam #add 5++----------------------------------------------------------------------------+-- Deconstruction+----------------------------------------------------------------------------++-- | This type can store any value that satisfies a certain constraint.+data ConstrainedSome (c :: Kind.Type -> Constraint) where+  ConstrainedSome :: c a => a -> ConstrainedSome c++instance Show (ConstrainedSome Show) where+  show (ConstrainedSome a) = show a++instance Buildable (ConstrainedSome Buildable) where+  build (ConstrainedSome a) = build a++-- | This class is needed to implement `unpackUParam`.+class UnpackUParam (c :: Kind.Type -> Constraint) entries where+  -- | Turn 'UParam' into a Haskell value.+  -- Since we don't know its type in compile time, we have to erase it using+  -- 'ConstrainedSome'. The user of this function can require arbitrary+  -- constraint to hold (depending on how they want to use the result).+  unpackUParam ::+    UParam entries -> Either EntryPointLookupError (MText, ConstrainedSome c)++instance UnpackUParam c '[] where+  unpackUParam (UParamUnsafe (name, _)) = Left (NoSuchEntryPoint name)++instance+  ( KnownSymbol name+  , UnpackUParam c entries+  , NiceUnpackedValue arg+  , c arg+  ) => UnpackUParam c ((name ?: arg) ': entries) where+  unpackUParam (UParamUnsafe (name, bytes))+    | name == symbolToMText @name =+      fmap (name,) .+      first (const ArgumentUnpackFailed) .+      fmap ConstrainedSome .+      lUnpackValue @arg $+      bytes+    | otherwise = unpackUParam @c @entries (UParamUnsafe (name, bytes))++----------------------------------------------------------------------------+-- Pattern-matching+----------------------------------------------------------------------------++-- | Helper instruction which extracts content of 'UParam'.+unwrapUParam :: UParam entries : s :-> (MText, ByteString) : s+unwrapUParam = coerce_++-- | Wrapper for a single "case" branch.+data CaseClauseU inp out (entry :: EntryPointKind) where+  CaseClauseU :: (arg : inp) :-> out -> CaseClauseU inp out '(name, arg)++instance (name ~ name', body ~ ((arg : inp) :-> out)) =>+         CaseArrow name' body (CaseClauseU inp out '(name, arg)) where+  (/->) _ = CaseClauseU++data EntryPointLookupError+  = NoSuchEntryPoint MText+  | ArgumentUnpackFailed+  deriving stock (Generic, Eq, Show)++instance Buildable EntryPointLookupError where+  build =+    \case+      NoSuchEntryPoint name -> "No such entrypoint: " <> build name+      ArgumentUnpackFailed -> "UNPACK failed"++type instance ErrorArg "uparamNoSuchEntryPoint" = MText+type instance ErrorArg "uparamArgumentUnpackFailed" = ()++instance Buildable (CustomError "uparamNoSuchEntryPoint") where+  build (CustomError _ name) = "No such entrypoint: " <> build name++instance Buildable (CustomError "uparamArgumentUnpackFailed") where+  build (CustomError _ ()) = "UNPACK failed"++instance CustomErrorHasDoc "uparamNoSuchEntryPoint" where+  customErrClass = ErrClassBadArgument+  customErrDocMdCause = "Entrypoint with given name does not exist."++instance CustomErrorHasDoc "uparamArgumentUnpackFailed" where+  customErrClass = ErrClassBadArgument+  customErrDocMdCause = "Argument of wrong type is provided to the entrypoint."++-- | Implementations of some entry points.+--+-- Note that this thing inherits properties of 'Rec', e.g. you can+-- @Data.Vinyl.Core.rappend@ implementations for two entry point sets+-- when assembling scattered parts of a contract.+type EntryPointsImpl inp out entries =+  Rec (CaseClauseU inp out) entries++-- | An action invoked when user-provided entry point is not found.+type UParamFallback inp out = ((MText, ByteString) : inp) :-> out++-- | Default implementation for 'UParamFallback', simply reports an error.+uparamFallbackFail :: UParamFallback inp out+uparamFallbackFail =+  car # failCustom #uparamNoSuchEntryPoint++-- | Make up a "case" over entry points.+class CaseUParam (entries :: [EntryPointKind]) where+  -- | Pattern-match on given @UParam entries@.+  --+  -- You have to provide all case branches and a fallback action on case+  -- when entry point is not found.+  --+  -- This function is unsafe because it does not make sure at type-level+  -- that entry points' names do not repeat.+  caseUParamUnsafe+    :: Rec (CaseClauseU inp out) entries+    -> UParamFallback inp out+    -> (UParam entries : inp) :-> out++instance CaseUParam '[] where+  caseUParamUnsafe RNil fallback = unwrapUParam # fallback++instance ( KnownSymbol name+         , CaseUParam entries+         , NiceUnpackedValue arg+         ) =>+         CaseUParam ((name ?: arg) ': entries) where+  caseUParamUnsafe (CaseClauseU clause :& clauses) fallback =+    dup # unwrapUParam # car #+    push (mkMTextUnsafe $ symbolValT' @name) # eq #+    if_ (unwrapUParam # cdr # unpack #+         ifSome nop (failCustom_ #uparamArgumentUnpackFailed) # clause)+        (cutUParamEntry # caseUParamUnsafe clauses fallback)+    where+      cutUParamEntry :: UParam (e : es) : s :-> UParam es : s+      cutUParamEntry = coerce_++-- | Pattern-match on given @UParam entries@.+--+-- You have to provide all case branches and a fallback action on case+-- when entry point is not found.+caseUParam+  :: (CaseUParam entries, RequireUniqueEntryPoints entries)+  => Rec (CaseClauseU inp out) entries+  -> UParamFallback inp out+  -> (UParam entries : inp) :-> out+caseUParam = caseUParamUnsafe++-- | Like 'caseUParam', but accepts a tuple of clauses, not a 'Rec'.+caseUParamT+  :: forall entries inp out clauses.+     ( clauses ~ Rec (CaseClauseU inp out) entries+     , RecFromTuple clauses+     , CaseUParam entries+     )+  => IsoRecTuple clauses+  -> UParamFallback inp out+  -> (UParam entries : inp) :-> out+caseUParamT clauses fallback = caseUParamUnsafe (recFromTuple clauses) fallback++-- Example+----------------------------------------------------------------------------++_caseSample :: UParam MyEntryPoints : s :-> Integer : s+_caseSample = caseUParamT+  ( #add /-> nop+  , #reset /-> L.drop @() # push 0+  ) uparamFallbackFail++----------------------------------------------------------------------------+-- ADT conversion+----------------------------------------------------------------------------++{- @martoon: I actually hope no one will use this capability,+   it's here primarily because in other places we also use Generic stuff.++   Representation with type-level list and a datatype made polymorhpic over+   it seems more powerful than Generics.+   1. It's simpler to implement features for it. No extra boilerplate.+   2. 'Data.Vinyl' provides many useful utilities to work with such things.+   3. You are not such constrained in selecting names of entry points as when+      they come from constructor names.+-}++-- | Make up 'UParam' from ADT sum.+--+-- Entry points template will consist of+-- @(constructorName, constructorFieldType)@ pairs.+-- Each constructor is expected to have exactly one field.+uparamFromAdt+  :: UParamLinearize up+  => up -> UParam (UParamLinearized up)+uparamFromAdt = adtToRec . G.from++-- | Constraint required by 'uparamFromAdt'.+type UParamLinearize p = (Generic p, GUParamLinearize (G.Rep p))++-- | Entry points template derived from given ADT sum.+type UParamLinearized p = GUParamLinearized (G.Rep p)++-- | Generic traversal for conversion between ADT sum and 'UParam'.+class GUParamLinearize (x :: Kind.Type -> Kind.Type) where+  type GUParamLinearized x :: [(Symbol, Kind.Type)]+  adtToRec :: x p -> UParam (GUParamLinearized x)++instance GUParamLinearize x => GUParamLinearize (G.D1 i x) where+  type GUParamLinearized (G.D1 i x) = GUParamLinearized x+  adtToRec = adtToRec . G.unM1++instance (GUParamLinearize x, GUParamLinearize y) => GUParamLinearize (x :+: y) where+  type GUParamLinearized (x :+: y) = GUParamLinearized x ++ GUParamLinearized y+  adtToRec = \case+    G.L1 x -> let UParamUnsafe up = adtToRec x in UParamUnsafe up+    G.R1 y -> let UParamUnsafe up = adtToRec y in UParamUnsafe up++instance (KnownSymbol name, NicePackedValue a) =>+         GUParamLinearize (G.C1 ('G.MetaCons name _1 _2) (G.S1 si (G.Rec0 a))) where+  type GUParamLinearized (G.C1 ('G.MetaCons name _1 _2) (G.S1 si (G.Rec0 a))) =+    '[ '(name, a) ]++  adtToRec (G.M1 (G.M1 (G.K1 a))) = UParamUnsafe+    ( symbolToMText @name+    , lPackValue a+    )++instance+    TypeError ('Text "UParam linearization requires exactly one field \+                    \in each constructor") =>+    GUParamLinearize (G.C1 i G.U1) where+  type GUParamLinearized (G.C1 i G.U1) =+    TypeError ('Text "Bad linearized ADT")+  adtToRec = error "impossible"++instance+    TypeError ('Text "UParam linearization requires exactly one field \+                    \in each constructor") =>+    GUParamLinearize (G.C1 i (x :*: y)) where+  type GUParamLinearized (G.C1 i (x :*: y)) =+    TypeError ('Text "Bad linearized ADT")+  adtToRec = error "impossible"++----------------------------------------------------------------------------+-- Documentation+----------------------------------------------------------------------------++instance Typeable interface => TypeHasDoc (UParam interface) where+  typeDocName _ = "Upgradable parameter"+  typeDocMdReference p = customTypeDocMdReference ("UParam", DType p) []+  typeDocMdDescription = "<UParam description>"+  typeDocHaskellRep = homomorphicTypeDocHaskellRep+  typeDocMichelsonRep = homomorphicTypeDocMichelsonRep++-- | Note that calling given entrypoints involves constructing 'UParam'.+pbsUParam :: forall ctorName. KnownSymbol ctorName => ParamBuildingStep+pbsUParam =+  let ctor = build $ symbolValT' @ctorName+  in ParamBuildingStep+      { pbsEnglish =+          "Wrap into *UParam* as " <> mdTicked ctor <> " entry point."+      , pbsHaskell =+          \a -> "mkUParam #" <> ctor <> " (" <> a <> ")"+      , pbsMichelson =+          \a -> "Pair \"" <> ctor <> "\" (pack (" <> a <> "))"+      }
+ src/Lorentz/UStore.hs view
@@ -0,0 +1,92 @@+{- | This module contains implementation of 'UStore'.++@UStore@ is essentially 'Lorentz.Store.Store' modified for the sake of+upgradeability.++In API it differs from @Store@ in the following ways:+1. It keeps both virtual @big_map@s and plain fields;+2. Neat conversion between Michelson and Haskell values+is implemented;+3. Regarding composabililty, one can operate with one @UStore@+and then lift it to a bigger one which includes the former.+This allows for simpler management of stores and clearer error messages.+In spite of this, operations with 'UStore's over deeply nested templates will+still work as before.++We represent 'UStore' as @big_map bytes bytes@.++* Plain fields are stored as+@key = pack fieldName; value = pack originalValue@.++* Virtual @big_map@s are kept as+@key = pack (bigMapName, originalKey); value = pack originalValue@.++-}+module Lorentz.UStore+  ( -- * UStore and related type definitions+    UStore+  , type (|~>)(..)+  , UStoreFieldExt (..)+  , UStoreField+  , UStoreMarkerType+  , KnownUStoreMarker (..)++    -- ** Type-lookup-by-name+  , GetUStoreKey+  , GetUStoreValue+  , GetUStoreField+  , GetUStoreFieldMarker++    -- ** Instructions+  , ustoreMem+  , ustoreGet+  , ustoreUpdate+  , ustoreInsert+  , ustoreInsertNew+  , ustoreDelete++  , ustoreToField+  , ustoreGetField+  , ustoreSetField++    -- ** Instruction constraints+  , HasUStore+  , HasUField+  , HasUStoreForAllIn++    -- * UStore composability+  , liftUStore+  , unliftUStore++    -- * UStore management from Haskell+  , UStoreConversible+  , mkUStore+  , ustoreDecompose+  , ustoreDecomposeFull+  , fillUStore++    -- * Migrations+  , InitUStore+  , MigrationScript (..)+  , UStoreMigration+  , UStoreMigrationT+  , migrationToScript+  , migrationToLambda+  , mkUStoreMigration+  , mustoreToOld+  , migrateGetField+  , migrateAddField+  , migrateRemoveField+  , migrateExtractField+  , migrateOverwriteField++    -- * Extras+  , PickMarkedFields+  ) where++import Lorentz.UStore.Types+import Lorentz.UStore.Instr+import Lorentz.UStore.Instances ()+import Lorentz.UStore.Haskell+import Lorentz.UStore.Lift+import Lorentz.UStore.Migration
+ src/Lorentz/UStore/Common.hs view
@@ -0,0 +1,13 @@+module Lorentz.UStore.Common+  ( fieldNameToMText+  ) where++import GHC.TypeLits (KnownSymbol, symbolVal)++import Michelson.Text++fieldNameToMText :: forall field. KnownSymbol field => MText+fieldNameToMText =+  -- Using 'mkMTextUnsafe' because our coding practices does not allow+  -- weird characters (like unicode) in field names+  mkMTextUnsafe . toText . symbolVal $ Proxy @field
+ src/Lorentz/UStore/Haskell.hs view
@@ -0,0 +1,335 @@+{-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++-- | Conversion between 'UStore' in Haskell and Michelson representation.+module Lorentz.UStore.Haskell+  ( UStoreContent+  , UStoreConversible+  , mkUStore+  , ustoreDecompose+  , ustoreDecomposeFull+  , fillUStore+  , migrateFillUStore+  , fillUStoreMigrationBlock+  ) where++import qualified Data.Kind as Kind+import qualified Data.List as L+import qualified Data.Map as Map+import Data.Singletons (demote)+import Fcf (type (=<<), Eval, Pure2)+import qualified Fcf+import Fmt ((+|), (+||), (|+), (||+))+import GHC.Generics ((:*:)(..), (:+:)(..))+import qualified GHC.Generics as G+import GHC.TypeLits (ErrorMessage(..), KnownSymbol, TypeError, symbolVal)++import Lorentz.Base+import Lorentz.Coercions+import Lorentz.Constraints+import qualified Lorentz.Instr as L+import Lorentz.Pack+import Lorentz.UStore.Common+import Lorentz.UStore.Migration+import Lorentz.UStore.Migration.Diff+import Lorentz.UStore.Types+import Michelson.Interpret.Pack+import Michelson.Text+import Michelson.Typed.Haskell.Value+import Util.Type++-- | 'UStore' content represented as key-value pairs.+type UStoreContent = [(ByteString, ByteString)]++-- | Make 'UStore' from separate @big_map@s and fields.+mkUStore+  :: (UStoreConversible template)+  => template -> UStore template+mkUStore = UStore . BigMap . mkUStoreRec++-- | Decompose 'UStore' into separate @big_map@s and fields.+--+-- Since this function needs to @UNPACK@ content of @UStore@ to actual+-- keys and values, you have to provide 'UnpackEnv'.+--+-- Along with resulting value, you get a list of @UStore@ entries which+-- were not recognized as belonging to any submap or field according to+-- @UStore@'s template - this should be empty unless @UStore@ invariants+-- were violated.+ustoreDecompose+  :: forall template.+     (UStoreConversible template)+  => UStore template -> Either Text (UStoreContent, template)+ustoreDecompose = storeDecomposeRec . Map.toList . unBigMap . unUStore++-- | Make migration script which initializes 'UStore' from scratch.+fillUStore+  :: (UStoreConversible template)+  => template -> UStoreMigrationT () template+fillUStore v = UStoreMigration $ appEndo (fillUStoreRec v) []++-- | Version of 'migrateFillUStore' for batched migrations.+--+-- Each field write will be placed to a separate batch.+fillUStoreMigrationBlock+  :: ( UStoreConversible template+     , allFieldsExp ~ AllUStoreFieldsF template+     , newDiff ~ FillingNewDiff template diff+     , newTouched ~ FillingNewTouched template touched+     , PatternMatchL newDiff, PatternMatchL newTouched+     )+  => template+  -> MigrationBlocks oldTempl newTempl diff touched newDiff newTouched+fillUStoreMigrationBlock v = MigrationBlocks $ appEndo (fillUStoreRec v) []++-- | Fill 'UStore' with entries from the given template as part of simple+-- migration.+--+-- Sometimes you already have some fields initialized and 'fillUStore' does not+-- suit, then in case if your UStore template is a nested structure you can use+-- sub-templates to initialize the corresponding parts of UStore.+--+-- For batched migrations see 'fillUStoreMigrationBlock'.+migrateFillUStore+  :: ( UStoreConversible template+     , allFieldsExp ~ AllUStoreFieldsF template+     , newDiff ~ FillingNewDiff template diff+     , newTouched ~ FillingNewTouched template touched+     , PatternMatchL newDiff, PatternMatchL newTouched+     )+  => template+  -> Lambda+       (MUStore oldTempl newTempl diff touched)+       (MUStore oldTempl newTempl newDiff newTouched)+migrateFillUStore v =+  let atoms = appEndo (fillUStoreRec v) []+      script = foldMap (unMigrationScript . maScript) atoms+  in coerce_ # script # coerce_++type FillingNewDiff template diff =+  CoverDiffMany diff+    (Eval (Fcf.Map (Pure2 '(,) 'DcAdd) =<< LinearizeUStoreF template))++type FillingNewTouched template touched =+  Eval (AllUStoreFieldsF template) ++ touched++-- Implementation+----------------------------------------------------------------------------++-- | Like 'ustoreDecompose', but requires all entries from @UStore@ to be+-- recognized.+ustoreDecomposeFull+  :: forall template.+     (UStoreConversible template)+  => UStore template -> Either Text template+ustoreDecomposeFull ustore = do+  (remained, res) <- ustoreDecompose ustore+  unless (null remained) $+    Left $ "Unrecognized entries in UStore: " +|| remained ||+ ""+  return res++-- | Recursive template traversal for 'mkUStore'.+mkUStoreRec+  :: (UStoreConversible template)+  => template -> Map ByteString ByteString+mkUStoreRec = gUstoreToVal . G.from++-- | Recursive template traversal for 'ustoreDecompose'.+storeDecomposeRec+  :: forall template.+     (UStoreConversible template)+  => UStoreContent -> Either Text (UStoreContent, template)+storeDecomposeRec = fmap (second G.to) ... gUstoreFromVal++-- | Recursive template traversal for 'fillUStore'.+fillUStoreRec+  :: (UStoreConversible template)+  => template+  -> Endo [MigrationAtom]+fillUStoreRec = gUstoreToScript . G.from++-- | Given template can be converted to 'UStore' value.+class (Generic template, GUStoreConversible (G.Rep template)) =>+       UStoreConversible template+instance (Generic template, GUStoreConversible (G.Rep template)) =>+         UStoreConversible template++-- | Generic traversal for 'mkUStore' and 'ustoreDecompose'.+class GUStoreConversible (template :: Kind.Type -> Kind.Type) where+  -- | Convert generic value to internal 'UStore' representation.+  gUstoreToVal :: template p -> Map ByteString ByteString++  -- | Parse internal 'UStore' representation into generic Haskell value of+  -- 'UStore', also returning unparsed entries.+  gUstoreFromVal+    :: UStoreContent+    -> Either Text (UStoreContent, template p)++  -- | Convert generic value to a script filling the corresponding 'UStore'.+  gUstoreToScript+    :: template p+    -> Endo [MigrationAtom]++instance GUStoreConversible x => GUStoreConversible (G.D1 i x) where+  gUstoreToVal = gUstoreToVal . G.unM1+  gUstoreFromVal = fmap (second G.M1) ... gUstoreFromVal+  gUstoreToScript = gUstoreToScript . G.unM1++instance GUStoreConversible x => GUStoreConversible (G.C1 i x) where+  gUstoreToVal = gUstoreToVal . G.unM1+  gUstoreFromVal = fmap (second G.M1) ... gUstoreFromVal+  gUstoreToScript = gUstoreToScript . G.unM1++instance TypeError ('Text "Unexpected sum type in UStore template") =>+         GUStoreConversible (x :+: y) where+  gUstoreToVal = error "impossible"+  gUstoreFromVal = error "impossible"+  gUstoreToScript = error "impossible"++instance TypeError ('Text "UStore template should have one constructor") =>+         GUStoreConversible G.V1 where+  gUstoreToVal = error "impossible"+  gUstoreFromVal = error "impossible"+  gUstoreToScript = error "impossible"++instance (GUStoreConversible x, GUStoreConversible y) =>+         GUStoreConversible (x :*: y) where+  gUstoreToVal (x :*: y) = gUstoreToVal x <> gUstoreToVal y+  gUstoreFromVal entries = do+    (entries', res1) <- gUstoreFromVal entries+    (entries'', res2) <- gUstoreFromVal entries'+    return (entries'', res1 :*: res2)+  gUstoreToScript (x :*: y) = gUstoreToScript x <> gUstoreToScript y++instance GUStoreConversible G.U1 where+  gUstoreToVal G.U1 = mempty+  gUstoreFromVal entries = pure (entries, G.U1)+  gUstoreToScript G.U1 = mempty++-- | Case of nested template.+instance {-# OVERLAPPABLE #-}+         (UStoreConversible template) =>+         GUStoreConversible (G.S1 i (G.Rec0 template)) where+  gUstoreToVal = mkUStoreRec . G.unK1 . G.unM1+  gUstoreFromVal = fmap (second $ G.M1 . G.K1) ... storeDecomposeRec+  gUstoreToScript = fillUStoreRec . G.unK1 . G.unM1++-- | Case of '|~>'.+instance ( NiceFullPackedValue k, NiceFullPackedValue v+         , KnownSymbol fieldName, Ord k+         ) =>+         GUStoreConversible (G.S1 ('G.MetaSel ('Just fieldName) _1 _2 _3)+                                  (G.Rec0 (k |~> v))) where+  gUstoreToVal (G.M1 (G.K1 (UStoreSubMap m))) =+    mconcat+      [ one ( lPackValue (fieldNameToMText @fieldName, k)+            , lPackValue v+            )+      | (k, v) <- Map.toList m+      ]++  gUstoreFromVal allEntries = do+    (unrecognized, res) <- foldM parseEntry (mempty, mempty) allEntries+    return (unrecognized, G.M1 . G.K1 $ UStoreSubMap res)+    where+    parseEntry+      :: (UStoreContent, Map k v)+      -> (ByteString, ByteString)+      -> Either Text (UStoreContent, Map k v)+    parseEntry (entries, !acc) entry@(key, val) =+      case lUnpackValue key of+        Left _ -> Right (entry : entries, acc)+        Right (name :: MText, keyValue :: k)+          | toText name /= toText (symbolVal $ Proxy @fieldName) ->+              Right (entry : entries, acc)+          | otherwise ->+            case lUnpackValue val of+              Left err ->+                Left $ "Failed to parse UStore value for " +|+                      demote @(ToT k) |+ " |~> " +| demote @(ToT v) |++                      ": " +| err |+ ""+              Right valValue ->+                Right (entries, Map.insert keyValue valValue acc)++  gUstoreToScript (G.M1 (G.K1 (UStoreSubMap m))) = Endo . (<>) $+    Map.toList m <&> \(k, v) ->+    formMigrationAtom Nothing $+      attachMigrationActionName (DAddAction "init submap") (fromLabel @fieldName) (Proxy @v) #+      -- @PUSH + PACK@ will be merged by optimizer, but there is still place+      -- for further improvement both or value and key pushing.+      -- We cannot push already packed value because that would break code+      -- analyzers and transformers, consider adding necessary rules to+      -- optimizer.+      -- TODO [TM-379]: consider improving this case+      -- or+      -- TODO: add necessary rules to optimizer+      L.push v # L.pack # L.some #+      L.push k # L.push (fieldNameToMText @fieldName) # L.pair # L.pack #+      L.update++-- | Case of 'UStoreField'.+instance (NiceFullPackedValue v, KnownUStoreMarker m, KnownSymbol fieldName) =>+         GUStoreConversible (G.S1 ('G.MetaSel ('Just fieldName) _1 _2 _3)+                                  (G.Rec0 (UStoreFieldExt m v))) where+  gUstoreToVal (G.M1 (G.K1 (UStoreField val))) =+    one ( mkFieldMarkerUKey @m (fromLabel @fieldName)+        , lPackValue val+        )++  gUstoreFromVal entries =+    let key = packValue' $ toVal (fieldNameToMText @fieldName)+    in case L.partition ((== key) . fst) entries of+        ([], _) ->+          Left $ "Failed to find field in UStore: " +|+                fieldNameToMText @fieldName |+ ""+        ([(_, val)], otherEntries) ->+          case lUnpackValue val of+            Left err ->+              Left $ "Failed to parse UStore value for field " +|+                    demote @(ToT v) |+ ": " +| err |+ ""+            Right valValue ->+              Right (otherEntries, G.M1 . G.K1 $ UStoreField valValue)+        (_ : _ : _, _) ->+          error "UStore content contained multiple entries with the same key"++  gUstoreToScript (G.M1 (G.K1 (UStoreField val))) =+    Endo . (:) . formMigrationAtom Nothing $+      attachMigrationActionName (DAddAction "init field") (fromLabel @fieldName) (Proxy @v) #+      -- Not pushing already packed value (which would be more efficient) because+      -- analyzers cannot work with packed values.+      -- TODO: make optimizer compress this to @push (Just $ lPackValue val)@+      L.push val # L.pack # L.some #++      L.push (mkFieldMarkerUKey @m (fromLabel @fieldName)) #+      L.update++-- Examples+----------------------------------------------------------------------------++data MyStoreTemplate = MyStoreTemplate+  { ints :: Integer |~> ()+  , flag :: UStoreField Bool+  }+  deriving stock (Generic)++data MyStoreTemplateBig = MyStoreTemplateBig+  { templ :: MyStoreTemplate+  , bytes :: ByteString |~> ByteString+  }+  deriving stock (Generic)++_storeSample :: UStore MyStoreTemplate+_storeSample = mkUStore+  MyStoreTemplate+  { ints = UStoreSubMap $ one (1, ())+  , flag = UStoreField False+  }++_storeSampleBig :: UStore MyStoreTemplateBig+_storeSampleBig = mkUStore $+  MyStoreTemplateBig+    MyStoreTemplate+      { ints = UStoreSubMap $ one (1, ())+      , flag = UStoreField False+      }+    (UStoreSubMap $ one ("a", "b"))
+ src/Lorentz/UStore/Instances.hs view
@@ -0,0 +1,24 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module Lorentz.UStore.Instances () where++import Lorentz.StoreClass+import Lorentz.UStore.Instr+import Lorentz.UStore.Types++instance HasUField fname ftype templ =>+         StoreHasField (UStore templ) fname ftype where+  storeFieldOps = StoreFieldOps+    { sopToField = ustoreToField+    , sopSetField = ustoreSetField+    }++instance HasUStore mname key value templ =>+         StoreHasSubmap (UStore templ) mname key value where+  storeSubmapOps = StoreSubmapOps+    { sopMem = ustoreMem+    , sopGet = ustoreGet+    , sopUpdate = ustoreUpdate+    , sopDelete = Just ustoreDelete+    , sopInsert = Just ustoreInsert+    }
+ src/Lorentz/UStore/Instr.hs view
@@ -0,0 +1,353 @@+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++-- | Instructions to work with 'UStore'.+module Lorentz.UStore.Instr+  ( unsafeEmptyUStore+  , ustoreMem+  , ustoreGet+  , ustoreUpdate+  , ustoreInsert+  , ustoreInsertNew+  , ustoreDelete++  , ustoreToField+  , ustoreGetField+  , ustoreSetField+  , ustoreRemoveFieldUnsafe++    -- ** Instruction constraints+  , HasUStore+  , HasUField+  , HasUStoreForAllIn++    -- ** Internals+  , packSubMapUKey+  ) where++import qualified Data.Kind as Kind+import GHC.Generics ((:*:), (:+:))+import qualified GHC.Generics as G+import Data.Vinyl.Derived (Label)+import GHC.TypeLits (KnownSymbol, Symbol)+import Type.Reflection ((:~:)(Refl))++import Lorentz.Base+import Lorentz.Coercions (coerce_)+import Lorentz.Errors+import Lorentz.Instr as L+import Lorentz.Macro+import Lorentz.Constraints+import Lorentz.UStore.Types+import Lorentz.UStore.Common+import Michelson.Text+import Michelson.Typed.Haskell.Value++-- Helpers+----------------------------------------------------------------------------++type KeyAccessC store name =+  ( NiceFullPackedValue (GetUStoreKey store name)+  , KnownSymbol name+  )++type ValueAccessC store name =+  ( NiceFullPackedValue (GetUStoreValue store name)+  , KnownSymbol name+  )++type FieldAccessC store name =+  ( NiceFullPackedValue (GetUStoreField store name)+  , KnownUStoreMarker (GetUStoreFieldMarker store name)+  , KnownSymbol name+  )++packSubMapUKey+  :: forall (field :: Symbol) k s.+     (KnownSymbol field, NicePackedValue k)+  => (k : s) :-> (ByteString : s)+packSubMapUKey = push submapName # pair # pack+  where+    submapName = fieldNameToMText @field++unpackUValueUnsafe+  :: forall (field :: Symbol) val s.+     (KnownSymbol field, NiceUnpackedValue val)+  => (ByteString : s) :-> (val : s)+unpackUValueUnsafe = unpack @val # ifSome nop (failUsing failErr)+  where+    failErr = mconcat+      [ [mt|UStore: failed to unpack |]+      , fieldNameToMText @field+      ]++-- Main instructions+----------------------------------------------------------------------------++-- | Put an empty 'UStore' onto the stack. This function is generally unsafe:+-- if store template contains a 'UStoreField', the resulting 'UStore' is not+-- immediately usable.+-- If you are sure that 'UStore' contains only submaps, feel free to just use+-- the result of this function. Otherwise you must set all fields.+unsafeEmptyUStore :: forall store s. s :-> UStore store ': s+unsafeEmptyUStore = emptyBigMap # coerce_ @(BigMap ByteString ByteString)++ustoreMem+  :: forall store name s.+     (KeyAccessC store name)+  => Label name+  -> GetUStoreKey store name : UStore store : s :-> Bool : s+ustoreMem _ = packSubMapUKey @name # mem++ustoreGet+  :: forall store name s.+     (KeyAccessC store name, ValueAccessC store name)+  => Label name+  -> GetUStoreKey store name : UStore store : s+       :-> Maybe (GetUStoreValue store name) : s+ustoreGet _ =+  packSubMapUKey @name #+  L.get #+  lmap (unpackUValueUnsafe @name @(GetUStoreValue store name))++ustoreUpdate+  :: forall store name s.+     (KeyAccessC store name, ValueAccessC store name)+  => Label name+  -> GetUStoreKey store name+      : Maybe (GetUStoreValue store name)+      : UStore store+      : s+  :-> UStore store : s+ustoreUpdate _ =+  packSubMapUKey @name #+  dip (lmap pack) #+  update++ustoreInsert+  :: forall store name s.+     (KeyAccessC store name, ValueAccessC store name)+  => Label name+  -> GetUStoreKey store name+      : GetUStoreValue store name+      : UStore store+      : s+  :-> UStore store : s+ustoreInsert _ =+  packSubMapUKey @name #+  dip (pack # L.some) #+  update++-- | Insert a key-value pair, but fail if it will overwrite some existing entry.+ustoreInsertNew+  :: forall store name s.+     (KeyAccessC store name, ValueAccessC store name)+  => Label name+  -> (forall s0 any. GetUStoreKey store name : s0 :-> any)+  -> GetUStoreKey store name+      : GetUStoreValue store name+      : UStore store+      : s+  :-> UStore store : s+ustoreInsertNew label doFail =+  duupX @3 # duupX @2 # ustoreMem label #+  if_ doFail (ustoreInsert label)++ustoreDelete+  :: forall store name s.+     (KeyAccessC store name)+  => Label name+  -> GetUStoreKey store name : UStore store : s+     :-> UStore store : s+ustoreDelete _ =+  packSubMapUKey @name #+  dip none #+  update++-- | Like 'toField', but for 'UStore'.+--+-- This may fail only if 'UStore' was made up incorrectly during contract+-- initialization.+ustoreToField+  :: forall store name s.+     (FieldAccessC store name)+  => Label name+  -> UStore store : s+     :-> GetUStoreField store name : s+ustoreToField l =+  push (mkFieldUKey @store l) #+  L.get #+  ensureFieldIsPresent #+  unpackUValueUnsafe @name @(GetUStoreField store name)+  where+    ensureFieldIsPresent =+      ifSome nop $ failUsing $ mconcat+        [ [mt|UStore: no field |]+        , fieldNameToMText @name+        ]++-- | Like 'getField', but for 'UStore'.+--+-- This may fail only if 'UStore' was made up incorrectly during contract+-- initialization.+ustoreGetField+  :: forall store name s.+     (FieldAccessC store name)+  => Label name+  -> UStore store : s+     :-> GetUStoreField store name : UStore store : s+ustoreGetField label = dup # ustoreToField label++-- | Like 'setField', but for 'UStore'.+ustoreSetField+  :: forall store name s.+     (FieldAccessC store name)+  => Label name+  -> GetUStoreField store name : UStore store : s+     :-> UStore store : s+ustoreSetField l =+  pack # L.some #+  push (mkFieldUKey @store l) #+  L.update++-- | Remove a field from 'UStore', for internal purposes only.+ustoreRemoveFieldUnsafe+  :: forall store name s.+     (FieldAccessC store name)+  => Label name+  -> UStore store : s+     :-> UStore store : s+ustoreRemoveFieldUnsafe l =+  L.none #+  push (mkFieldUKey @store l) #+  L.update++-- | This constraint can be used if a function needs to work with+-- /big/ store, but needs to know only about some submap(s) of it.+--+-- It can use all UStore operations for a particular name, key and+-- value without knowing whole template.+type HasUStore name key value store =+   ( KeyAccessC store name, ValueAccessC store name+   , GetUStoreKey store name ~ key+   , GetUStoreValue store name ~ value+   )++-- | This constraint can be used if a function needs to work with+-- /big/ store, but needs to know only about some field of it.+type HasUField name ty store =+   ( FieldAccessC store name+   , GetUStoreField store name ~ ty+   )++-- | Write down all sensisble constraints which given @store@ satisfies+-- and apply them to @constrained@.+--+-- This store should have '|~>' and 'UStoreField' fields in its immediate fields,+-- no deep inspection is performed.+type HasUStoreForAllIn store constrained =+  (Generic store, GHasStoreForAllIn constrained (G.Rep store))++type family GHasStoreForAllIn (store :: Kind.Type) (x :: Kind.Type -> Kind.Type)+            :: Constraint where+  GHasStoreForAllIn store (G.D1 _ x) = GHasStoreForAllIn store x+  GHasStoreForAllIn store (x :+: y) =+    (GHasStoreForAllIn store x, GHasStoreForAllIn store y)+  GHasStoreForAllIn store (x :*: y) =+    (GHasStoreForAllIn store x, GHasStoreForAllIn store y)+  GHasStoreForAllIn store (G.C1 _ x) = GHasStoreForAllIn store x+  GHasStoreForAllIn store (G.S1 ('G.MetaSel ('Just name) _ _ _)+                            (G.Rec0 (key |~> value))) =+    HasUStore name key value store+  GHasStoreForAllIn store (G.S1 ('G.MetaSel ('Just name) _ _ _)+                            (G.Rec0 (UStoreFieldExt _ value))) =+    HasUField name value store+  GHasStoreForAllIn _ G.V1 = ()+  GHasStoreForAllIn _ G.U1 = ()++----------------------------------------------------------------------------+-- Examples+----------------------------------------------------------------------------++data MyStoreTemplate = MyStoreTemplate+  { ints :: Integer |~> ()+  , bytes :: ByteString |~> ByteString+  , flag :: UStoreField Bool+  , entrypoint :: UStoreFieldExt Marker1 Integer+  }+  deriving stock (Generic)++type MyStore = UStore MyStoreTemplate++data Marker1 :: UStoreMarkerType+  deriving anyclass KnownUStoreMarker++_sample1 :: Integer : MyStore : s :-> MyStore : s+_sample1 = ustoreDelete @MyStoreTemplate #ints++_sample2 :: ByteString : ByteString : MyStore : s :-> MyStore : s+_sample2 = ustoreInsert @MyStoreTemplate #bytes++_sample3 :: MyStore : s :-> Bool : s+_sample3 = ustoreToField @MyStoreTemplate #flag++_sample3'5 :: MyStore : s :-> Integer : s+_sample3'5 = ustoreToField @MyStoreTemplate #entrypoint++data MyStoreTemplate2 = MyStoreTemplate2+  { bools :: Bool |~> Bool+  , ints2 :: Integer |~> Integer+  , ints3 :: Integer |~> Bool+  }+  deriving stock (Generic)++newtype MyNatural = MyNatural Natural+  deriving newtype (IsoCValue, IsoValue)++data MyStoreTemplate3 = MyStoreTemplate3 { store3 :: Natural |~> MyNatural }+  deriving stock Generic++data MyStoreTemplateBig = MyStoreTemplateBig+  MyStoreTemplate+  MyStoreTemplate2+  MyStoreTemplate3+  deriving stock Generic++_MyStoreTemplateBigTextsStore ::+  GetUStore "bytes" MyStoreTemplateBig :~: 'MapSignature ByteString ByteString+_MyStoreTemplateBigTextsStore = Refl++_MyStoreTemplateBigBoolsStore ::+  GetUStore "bools" MyStoreTemplateBig :~: 'MapSignature Bool Bool+_MyStoreTemplateBigBoolsStore = Refl++_MyStoreTemplateBigMyStoreTemplate3 ::+  GetUStore "store3" MyStoreTemplateBig :~: 'MapSignature Natural MyNatural+_MyStoreTemplateBigMyStoreTemplate3 = Refl++type MyStoreBig = UStore MyStoreTemplateBig++_sample4 :: Integer : MyStoreBig : s :-> MyStoreBig : s+_sample4 = ustoreDelete #ints2++_sample5 :: ByteString : MyStoreBig : s :-> Bool : s+_sample5 = ustoreMem #bytes++_sample6 :: Natural : MyNatural : MyStoreBig : s :-> MyStoreBig : s+_sample6 = ustoreInsert #store3++-- | When you want to express a constraint like+-- "given big store contains all elements present in given small concrete store",+-- you can use 'HasUStoreForAllIn'.+--+-- Here @store@ is a big store, and we expect it to contain 'MyStoreTemplate'+-- entirely.+_sample7+  :: HasUStoreForAllIn MyStoreTemplate store+  => UStore store : s :-> Bool : Maybe ByteString : s+_sample7 = ustoreGetField #flag # dip (push "x" # ustoreGet #bytes)++-- | '_sample7' with @store@ instantiated to 'MyStoreTemplateBig'.+_sample7' :: UStore MyStoreTemplateBig : s :-> Bool : Maybe ByteString : s+_sample7' = _sample7
+ src/Lorentz/UStore/Lift.hs view
@@ -0,0 +1,112 @@+{-# LANGUAGE DerivingStrategies #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++-- | Composability helper for 'UStore'.+module Lorentz.UStore.Lift+  ( liftUStore+  , unliftUStore++    -- * Internals+  , UStoreFieldsAreUnique+  ) where++import Data.Vinyl.Derived (Label)+import Data.Type.Bool (If)+import qualified Data.Kind as Kind+import GHC.TypeLits (Symbol, TypeError, ErrorMessage (..))+import Data.Vinyl.TypeLevel (type (++))+import GHC.Generics (type (:+:), type (:*:))+import qualified GHC.Generics as G++import Lorentz.Base+import Lorentz.Coercions+import Lorentz.Instr+import Lorentz.UStore.Types+import Michelson.Typed.Haskell+import Util.Type++-- | Get all fields names accessible in given 'UStore' template.+type UStoreFields (template :: Kind.Type) = GUStoreFields (G.Rep template)++type family GUStoreFields (x :: Kind.Type -> Kind.Type) :: [Symbol] where+  -- We are not oblidged to fail in case of bad template - this will be handled+  -- in other operations with 'UStore' anyway.+  GUStoreFields (G.D1 _ x) = GUStoreFields x+  GUStoreFields (_ :+: _) = '[]+  GUStoreFields G.V1 = '[]+  GUStoreFields (G.C1 _ x) = GUStoreFields x+  GUStoreFields (x :*: y) = GUStoreFields x ++ GUStoreFields y+  GUStoreFields (G.S1 ('G.MetaSel ('Just fieldName) _ _ _) (G.Rec0 (_ |~> _))) =+    '[fieldName]+  GUStoreFields (G.S1 ('G.MetaSel ('Just fieldName) _ _ _) (G.Rec0 (UStoreFieldExt _ _))) =+    '[fieldName]+  GUStoreFields (G.S1 _ (G.Rec0 a)) =+    UStoreFields a++type UStoreFieldsAreUnique template = AllUnique (UStoreFields template)++type family RequireAllUniqueFields (template :: Kind.Type) :: Constraint where+  RequireAllUniqueFields template =+    If (UStoreFieldsAreUnique template)+       (() :: Constraint)+       (TypeError ('Text "Some field in template is duplicated"))+      -- TODO: if this ever fires for you and it's not clear which exact field+      -- is duplicated, please create a ticket to implement the corresponding+      -- logic.++-- | Lift an 'UStore' to another 'UStore' which contains all the entries+-- of the former under given field.+--+-- This function is not intended for use in migrations, only in normal+-- entry points.+--+-- Note that this function ensures that template of resulting store+-- does not contain inner nested templates with duplicated fields,+-- otherwise 'UStore' invariants could get broken.+liftUStore+  :: (Generic template, RequireAllUniqueFields template)+  => Label name+  -> UStore (GetFieldType template name) : s :-> UStore template : s+liftUStore _ = coerce_++-- | Unlift an 'UStore' to a smaller 'UStore' which is part of the former.+--+-- This function is not intended for use in migrations, only in normal+-- entry points.+--+-- Surprisingly, despite smaller 'UStore' may have extra entries,+-- this function is safe when used in contract code.+-- Truly, all getters and setters are still safe to use.+-- Also, there is no way for the resulting small @UStore@ to leak outside+-- of the contract since the only place where 'big_map' can appear+-- is contract storage, so this small @UStore@ can be either dropped+-- or lifted back via 'liftUStore' to appear as part of the new contract's state.+--+-- When this function is run as part of standalone instructions sequence,+-- not as part of contract code (e.g. in tests), you may get an @UStore@+-- with entries not inherent to it.+unliftUStore+  :: (Generic template)+  => Label name+  -> UStore template : s :-> UStore (GetFieldType template name) : s+unliftUStore _ = coerce_++-- Examples+----------------------------------------------------------------------------++data MyStoreTemplate = MyStoreTemplate+  { ints :: Integer |~> Integer+  } deriving stock Generic++data MyStoreTemplateBig = MyStoreTemplateBig+  { bool :: UStoreField Bool+  , substore :: MyStoreTemplate+  } deriving stock Generic++-- | This example demostrates a way to run an instruction, operating on small+-- 'UStore', so that it works on a larger 'UStore'.+_sampleWithMyStore+  :: ('[param, UStore MyStoreTemplate] :-> '[UStore MyStoreTemplate])+  -> ('[param, UStore MyStoreTemplateBig] :-> '[UStore MyStoreTemplateBig])+_sampleWithMyStore instr =+  dip (unliftUStore #substore) # instr # liftUStore #substore
+ src/Lorentz/UStore/Migration.hs view
@@ -0,0 +1,89 @@+{- | Type-safe migrations of UStore.++This implements imperative approach to migration when we make user+write a code of migration and track whether all new fields were indeed added+and all unnecessary fields were removed.++You can find migration examples in tests.++== How to write your simple migration++1. Start with migration template:++    @+    migration :: 'UStoreMigration' V1.Storage V2.Storage+    migration = 'mkUStoreMigration' $ do+      -- migration code to be put here+      'migrationFinish'+    @++    You will be prompted with a list of fields which should be added or removed.++2. Add/remove necessary fields using 'migrateAddField', 'migrateExtractField'+and other instructions.+They allow you to operate with 'MUStore' — it is similar to 'UStore'+but used within 'mkUStoreMigration' to track migration progress.++3. Use 'migrationToScript' or 'migrationToTestScript' to turn 'UStoreMigration'+into something useful.++Note that here you will get a solid 'MigrationScript', thus migration has+to fit into single Tezos transaction. If that's an issue, see the next section.++== How to write batched migration++1. Insert migration template.++    It looks like:++    @+    migration :: 'UStoreMigration' V1.Storage V2.Storage+    migration = 'mkUStoreBatchedMigration' $+      -- place for migration blocks+      'migrationFinish'+    @++2. Fill migration code with blocks like++    @+    'mkUStoreBatchedMigration' $+      'muBlock' '$:' do+        -- code for block 1+      '<-->'+      'muBlock' '$:' do+        -- code for block 2+      '<-->'+      'migrationFinish'+    @++    Migration blocks have to be the smallest actions which can safely be mixed+    and splitted accross migration stages.++3. Compile migration with 'compileBatchedMigration'.++    Here you have to supply batching implementation. Alternatives include++    * 'mbNoBatching';+    * 'mbBatchesAsIs';+    * Functions from 'Lorentz.UStore.Migration.Batching' module.++4. Get the required information about migration.++    * 'migrationToScripts' picks the migration scripts, each has to be put+      in a separate Tezos transaction.++    * 'buildMigrationPlan' - dump description of each migration stage.++== Manual migrations++If for some reasons you need to define migration manually, you can use+functions from @Manual migrations@ section of "Lorentz.UStore.Migration.Base".++-}+module Lorentz.UStore.Migration+  ( module Exports+  ) where++import Lorentz.UStore.Migration.Base as Exports+import Lorentz.UStore.Migration.Batching as Exports+import Lorentz.UStore.Migration.Blocks as Exports
+ src/Lorentz/UStore/Migration/Base.hs view
@@ -0,0 +1,460 @@+{-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++{- | Basic migration primitives.++All primitives in one scheme:+++                         MigrationBlocks+                   (batched migrations writing)+                    /|          ||+           muBlock //           || mkUStoreBatchedMigration+                  //            ||+                 //             ||+             MUStore            ||         UStore template value+    (simple migration writing)  ||       (storage initialization)+                    \\          ||         //+                     \\         ||        //+    mkUStoreMigration \\        ||       // fillUStore+                       \|       \/      |/+                         UStoreMigration+                        (whole migration)+                              ||    \\+                              ||     \\+            migrationToScript ||      \\ compileMigration+                              ||       \\                    MigrationBatching+                              ||        \\                (way to slice migration)+                              ||         \\                    //+                              ||          \\                  //+                              ||           \|                |/+                              ||         UStoreMigrationCompiled+                              ||           (sliced migration)+                              ||          //                 \\+                              ||    migrationToScripts        \\ buildMigrationPlan+                              ||        //                     \\ migrationStagesNum+                              ||       //                       \\ ...+                              \/      |/                         \|+                        MigrationScript                    Information about migration+                    (part of migration which            (migration plan, stages number...)+                  fits into Tezos transaction)++-}+module Lorentz.UStore.Migration.Base+  ( -- * 'UStore' utilities+    InitUStore+  , SomeUTemplate+  , UStore_+  , toUStore_+  , fromUStore_++    -- * Basic migration primitives+  , MigrationScript (..)+  , maNameL+  , maScriptL+  , maActionsDescL+  , MigrationAtom (..)+  , UStoreMigration (..)+  , UStoreMigrationT+  , MigrationBlocks (..)+  , MUStore (..)+  , migrationToLambda+  , mapMigrationCode++    -- ** Simple migrations+  , mkUStoreMigration+  , migrationToScript++    -- ** Batched migrations+  , MigrationBatching (..)+  , mbBatchesAsIs+  , mbNoBatching+  , compileMigration+  , UStoreMigrationCompiled (..)+  , mkUStoreBatchedMigration+  , migrationToScripts+  , migrationToScriptsList+  , migrationToInfo+  , migrationStagesNum+  , buildMigrationPlan++    -- * Manual migrations+  , manualWithUStore+  , manualConcatMigrationScripts++    -- * Extras+  , DMigrationActionType (..)+  , DMigrationActionDesc (..)+  , attachMigrationActionName++    -- * Internals+  , formMigrationAtom+  ) where++import Control.Lens (traversed, _Wrapped')+import Data.Default (def)+import qualified Data.Foldable as Foldable+import qualified Data.Kind as Kind+import Data.Singletons (SingI(..), demote)+import qualified Data.Typeable as Typeable+import Data.Vinyl.Derived (Label)+import Fmt (Buildable(..), Builder, fmt)++import Lorentz.Base+import Lorentz.Coercions+import Lorentz.Doc+import Lorentz.Instr (nop)+import Lorentz.Run+import Lorentz.UStore.Types+import Lorentz.Value+import Michelson.Typed (ExtInstr(..), Instr(..), T(..))+import Michelson.Typed.Util+import Util.Lens+import Util.TypeLits++import Lorentz.UStore.Migration.Diff++----------------------------------------------------------------------------+-- UStore utilities+----------------------------------------------------------------------------++-- | Absolutely empty storage.+type InitUStore = UStore ()++-- | Dummy template for 'UStore', use this when you want to forget exact template+-- and make type of store homomorphic.+data SomeUTemplate++-- | UStore with hidden template.+type UStore_ = UStore SomeUTemplate++toUStore_ :: UStore template -> UStore_+toUStore_ (UStore s) = (UStore s)++fromUStore_ :: UStore_ -> UStore template+fromUStore_ (UStore s) = (UStore s)++----------------------------------------------------------------------------+-- Migration primitives+----------------------------------------------------------------------------++-- | Code of migration for 'UStore'.+--+-- Invariant: preferably should fit into op size / gas limits (quite obvious).+-- Often this stands for exactly one stage of migration (one Tezos transaction).+newtype MigrationScript = MigrationScript+  { unMigrationScript :: Lambda UStore_ UStore_+  } deriving stock (Show, Generic)+    deriving anyclass IsoValue++instance Wrapped MigrationScript++instance TypeHasDoc MigrationScript where+  typeDocMdDescription =+    "A code which updates storage in order to make it compliant with the \+    \new version of the contract."++-- | Manually perform a piece of migration.+manualWithUStore+  :: forall ustore template.+      (ustore ~ UStore template)+  => ('[ustore] :-> '[ustore]) -> MigrationScript+manualWithUStore action = MigrationScript $ coerce_ # action # coerce_++-- | Merge several migration scripts. Used in manual migrations.+--+-- This function is generally unsafe because resulting migration script can fail+-- to fit into operation size limit.+manualConcatMigrationScripts :: [MigrationScript] -> MigrationScript+manualConcatMigrationScripts =+  MigrationScript . foldl' (#) nop . fmap unMigrationScript++-- | An action on storage entry.+data DMigrationActionType+  = DAddAction Text+    -- ^ Some sort of addition: "init", "set", "overwrite", e.t.c.+  | DDelAction+    -- ^ Removal.+  deriving (Show)++instance Buildable DMigrationActionType where+  build = \case+    DAddAction a -> build a+    DDelAction -> "remove"++-- | Describes single migration action.+--+-- In most cases it is possible to derive reasonable description for migration+-- atom automatically, this datatype exactly carries this information.+data DMigrationActionDesc = DMigrationActionDesc+  { manAction :: DMigrationActionType+    -- ^ Action on field, e.g. "set", "remove", "overwrite".+  , manField :: Text+    -- ^ Name of affected field of 'UStore'.+  , manFieldType :: T+    -- ^ Type of affected field of 'UStore' in new storage version.+  } deriving (Show)++-- Sad that we need to write this useless documentation instance, probably it's+-- worth generalizing @doc_group@ and @doc_item@ instructions so that they+-- could serve as multi-purpose markers.+instance DocItem DMigrationActionDesc where+  type DocItemPosition DMigrationActionDesc = 105010+  docItemSectionName = Nothing+  docItemToMarkdown _ _ = "Migration action"++-- | Add description of action, it will be used in rendering migration plan and+-- some batching implementations.+attachMigrationActionName+  :: (KnownSymbol fieldName, SingI (ToT fieldTy))+  => DMigrationActionType+  -> Label fieldName+  -> Proxy fieldTy+  -> s :-> s+attachMigrationActionName action (_ :: Label fieldName) (_ :: Proxy fieldTy) =+  doc $ DMigrationActionDesc+  { manAction = action+  , manField = symbolValT' @fieldName+  , manFieldType = demote @(ToT fieldTy)+  }++-- | Minimal possible piece of migration script.+--+-- Different atoms can be arbitrarily reordered and separated across migration+-- stages, but each single atom is treated as a whole.+--+-- Splitting migration into atoms is responsibility of migration writer.+data MigrationAtom = MigrationAtom+  { maName :: Text+  , maScript :: MigrationScript+  , maActionsDesc :: [DMigrationActionDesc]+  } deriving (Show)++makeLensesWith postfixLFields ''MigrationAtom++-- | Keeps information about migration between 'UStore's with two given+-- templates.+-- Note that it is polymorphic over whole storage types, not their templates,+-- for convenience (so that there is no need to export the template).+data UStoreMigration (oldStore :: Kind.Type) (newStore :: Kind.Type) where+  UStoreMigration+    :: (oldStore ~ UStore oldTemplate, newStore ~ UStore newTemplate)+    => [MigrationAtom]+    -> UStoreMigration oldStore newStore++-- | Alias for 'UStoreMigration' which accepts UStore templates+-- as type arguments.+type UStoreMigrationT ot nt = UStoreMigration (UStore ot) (UStore nt)++-- | Turn 'Migration' into a whole piece of code for transforming storage.+--+-- This is not want you'd want to use for contract deployment because of+-- gas and operation size limits that Tezos applies to transactions.+migrationToLambda+  :: UStoreMigrationT oldTemplate newTemplate+  -> Lambda (UStore oldTemplate) (UStore newTemplate)+migrationToLambda (UStoreMigration atoms) =+  coerce_ # foldMap (unMigrationScript . maScript) atoms # coerce_++-- | Modify all code in migration.+mapMigrationCode+  :: (forall i o. (i :-> o) -> (i :-> o))+  -> UStoreMigration os ns+  -> UStoreMigration os ns+mapMigrationCode f (UStoreMigration atoms) =+  UStoreMigration $+    atoms & traversed . maScriptL . _Wrapped' %~ f++-- | A bunch of migration atoms produced by migration writer.+newtype MigrationBlocks (oldTemplate :: Kind.Type) (newTemplate :: Kind.Type)+                        (preRemDiff :: [DiffItem]) (preTouched :: [Symbol])+                        (postRemDiff :: [DiffItem]) (postTouched :: [Symbol]) =+  MigrationBlocks [MigrationAtom]++{- | Wrapper over 'UStore' which is currently being migrated.++In type-level arguments it keeps++* Old and new 'UStore' templates - mostly for convenience of the implementation.++* Remaining diff which yet should be covered. Here we track migration progress.+Once remaining diff is empty, migration is finished.++* Names of fields which have already been touched by migration.+Required to make getters safe.+-}+newtype MUStore (oldTemplate :: Kind.Type) (newTemplate :: Kind.Type)+                (remDiff :: [DiffItem]) (touched :: [Symbol]) =+  MUStoreUnsafe (UStore oldTemplate)+  deriving stock Generic+  deriving anyclass IsoValue++-- | Create migration atom from code.+--+-- This is an internal function, should not be used for writing migrations.+formMigrationAtom+  :: Maybe Text+  -> Lambda UStore_ UStore_+  -> MigrationAtom+formMigrationAtom mname code =+  MigrationAtom+  { maName = name+  , maScript = MigrationScript (coerce_ # code # coerce_)+  , maActionsDesc = actionsDescs+  }+  where+    name = case mname of+      Just n -> n+      Nothing ->+        fmt . mconcat $ intersperse ", "+          [ build action <> " \"" <> build field <> "\""+          | DMigrationActionDesc action field _type <- actionsDescs+          ]++    actionsDescs =+      let instr = compileLorentz code+          (_, actions) = dfsInstr def (\i -> (i, pickActionDescs i)) instr+      in actions++    pickActionDescs :: Instr i o -> [DMigrationActionDesc]+    pickActionDescs i = case i of+      Ext (DOC_ITEM (SomeDocItem di)) ->+        [ d+        | Just d@DMigrationActionDesc{} <- pure $ Typeable.cast di+        ]+      _ -> []++-- | Way of distributing migration atoms among batches.+--+-- This also participates in describing migration plan and should contain+-- information which would clarify to a user why migration is splitted+-- such a way. Objects of type @batchInfo@ stand for information corresponding to+-- a batch and may include e.g. names of taken actions and gas consumption.+--+-- Type argument @structure@ stands for container where batches will be put to+-- and is usually a list ('[]').+--+-- When writing an instance of this datatype, you should tend to produce+-- as few batches as possible because Tezos transaction execution overhead+-- is quite high; though these batches should still preferably fit into gas limit.+--+-- Note that we never fail here because reaching perfect consistency with Tezos+-- gas model is beyond dreams for now, even if our model predicts that some+-- migration atom cannot be fit into gas limit, Tezos node can think differently+-- and accept the migration.+-- If your batching function can make predictions about fitting into gas limit,+-- consider including this information in @batchInfo@ type.+--+-- See batching implementations in "Lorentz.UStore.Migration.Batching" module.+data MigrationBatching (structure :: Kind.Type -> Kind.Type) (batchInfo :: Kind.Type) =+  MigrationBatching ([MigrationAtom] -> structure (batchInfo, MigrationScript))++-- | Put each migration atom to a separate batch.+--+-- In most cases this is not what you want, but may be useful if e.g. you write+-- your migration manually.+mbBatchesAsIs :: MigrationBatching [] Text+mbBatchesAsIs = MigrationBatching $+  map (maName &&& maScript)++-- | Put the whole migration into one batch.+mbNoBatching :: MigrationBatching Identity Text+mbNoBatching = MigrationBatching $+  Identity . \atoms ->+    ( mconcat . intersperse ", " $ maName <$> atoms+    , manualConcatMigrationScripts (maScript <$> atoms)+    )++-- | Version of 'mkUStoreMigration' which allows splitting migration in batches.+--+-- Here you supply a sequence of migration blocks which then are automatically+-- distributed among migration stages.+mkUStoreBatchedMigration+  :: MigrationBlocks oldTempl newTempl (BuildDiff oldTempl newTempl) '[] '[] _1+  -> UStoreMigrationT oldTempl newTempl+mkUStoreBatchedMigration (MigrationBlocks blocks) = UStoreMigration blocks++-- | Safe way to create migration scripts for 'UStore'.+--+-- You have to supply a code which would transform 'MUStore',+-- coverring required diff step-by-step.+-- All basic instructions work, also use @migrate*@ functions+-- from this module to operate with 'MUStore'.+--+-- This method produces a whole migration, it cannot be splitted in batches.+-- In case if your migration is too big to be applied within a single+-- transaction, use 'mkUStoreBatchedMigration'.+mkUStoreMigration+  :: Lambda+       (MUStore oldTempl newTempl (BuildDiff oldTempl newTempl) '[])+       (MUStore oldTempl newTempl '[] _1)+  -> UStoreMigrationT oldTempl newTempl+mkUStoreMigration code =+  mkUStoreBatchedMigration $+    MigrationBlocks . one . formMigrationAtom (Just "Migration") $+      coerce_ # code # coerce_++-- | Migration script splitted in batches.+--+-- This is an intermediate form of migration content and needed because+-- compiling 'UStoreMigration' is a potentially heavyweight operation,+-- and after compilation is performed you may need to get various information like+-- number of migration steps, migration script, migration plan and other.+newtype UStoreMigrationCompiled (structure :: Kind.Type -> Kind.Type) (batchInfo :: Kind.Type) =+  UStoreMigrationCompiled+  { compiledMigrationContent :: structure (batchInfo, MigrationScript)+  }++-- | Compile migration for use in production.+compileMigration+  :: MigrationBatching t batchInfo+  -> UStoreMigration ot nt+  -> UStoreMigrationCompiled t batchInfo+compileMigration (MigrationBatching toBatches) (UStoreMigration blks) =+  UStoreMigrationCompiled (toBatches blks)++-- | Get migration scripts, each to be executed in separate Tezos transaction.+migrationToScripts+  :: Traversable t+  => UStoreMigrationCompiled t batchInfo+  -> t MigrationScript+migrationToScripts = map snd . compiledMigrationContent++-- | Get migration scripts as list.+migrationToScriptsList+  :: Traversable t+  => UStoreMigrationCompiled t batchInfo+  -> [MigrationScript]+migrationToScriptsList = Foldable.toList . migrationToScripts++-- | Get migration script in case of simple (non-batched) migration.+migrationToScript+  :: UStoreMigration ot nt+  -> MigrationScript+migrationToScript =+  runIdentity . migrationToScripts . compileMigration mbNoBatching++-- | Get information about each batch.+migrationToInfo+  :: Traversable t+  => UStoreMigrationCompiled t batchInfo+  -> t batchInfo+migrationToInfo = map fst . compiledMigrationContent++-- | Number of stages in migration.+migrationStagesNum+  :: Traversable t+  => UStoreMigrationCompiled t batchInfo -> Int+migrationStagesNum = Foldable.length . migrationToScripts++-- | Render migration plan.+buildMigrationPlan+  :: (Traversable t, Buildable batchInfo)+  => UStoreMigrationCompiled t batchInfo -> Builder+buildMigrationPlan content =+  let infos = Foldable.toList $ migrationToInfo content+  in mconcat+     [ "Migration stages:\n"+     , mconcat $ zip [1..] infos <&> \(i :: Int, info) ->+        build i <> ") " <> build info <> "\n"+     ]
+ src/Lorentz/UStore/Migration/Batching.hs view
@@ -0,0 +1,113 @@+-- | Different approaches to batching.+--+-- For now we do not support perfect batching because operation size evaluation+-- (as well as gas consumption evaluation) is not implemented yet.+-- The only non-trivial batching implementation we provide is+-- 'mbSeparateLambdas'.+module Lorentz.UStore.Migration.Batching+  ( -- * Separate-lambdas batching+    SlBatchType (..)+  , SlBatchInfo (..)+  , mbSeparateLambdas+  ) where++import qualified Data.List as L+import Fmt (Buildable(..))+import System.Console.Pretty (Color(..), color)++import Lorentz.UStore.Migration.Base+import Michelson.Typed++----------------------------------------------------------------------------+-- Separating lambdas+----------------------------------------------------------------------------++-- | Type of batch.+data SlBatchType+  = SlbtData+    -- ^ Addition of any type of data.+  | SlbtLambda+    -- ^ Addition of code.+  | SlbtCustom+    -- ^ Several joined actions of different types.+  | SlbtUnknown+    -- ^ No information to chooseType about batching.+    -- This means that the given action does not contain 'DMigrationActionDesc'.+  deriving (Show, Eq)++slbtIsData :: SlBatchType -> Bool+slbtIsData = \case { SlbtData -> True; _ -> False }++data SlBatchInfo = SlBatchInfo+  { slbiType :: SlBatchType+  , slbiActions :: [Text]+  }++instance Buildable SlBatchInfo where+  build (SlBatchInfo ty actions) = mconcat+    [ build @Text $ case ty of+        SlbtData -> color Blue "[data]"+        SlbtLambda -> color Green "[code]"+        SlbtCustom -> color Yellow "[custom]"+        SlbtUnknown -> color Red "[unknown]"+    , " "+    , case actions of+        [] -> "-"+        [a] -> build a+        as -> foldMap (\a -> "\n  * " <> build a) as+    ]++-- | Puts all data updates in one batch, and all lambdas in separate batches,+-- one per batch.+--+-- The reason for such behaviour is that in production contracts amount of+-- changed data (be it in contract initialization or contract upgrade) is small,+-- while stored entrypoints are huge and addition of even one entrypoint often+-- barely fits into gas limit.+mbSeparateLambdas :: MigrationBatching [] SlBatchInfo+mbSeparateLambdas = MigrationBatching $ \atoms ->+  let+    atomsWithType = atoms <&> \a -> (atomType a, a)+    (dataAtoms, otherAtoms) = L.partition (slbtIsData . fst) atomsWithType+    dataMigration =+      ( SlBatchInfo SlbtData (nubCounting $ maName . snd <$> dataAtoms)+      , manualConcatMigrationScripts (maScript . snd <$> dataAtoms)+      )+    otherMigrations =+      [ (SlBatchInfo ty [maName atom], maScript atom)+      | (ty, atom) <- otherAtoms+      ]+  in dataMigration : otherMigrations+  where+    atomType :: MigrationAtom -> SlBatchType+    atomType = chooseType . maActionsDesc++    chooseType :: [DMigrationActionDesc] -> SlBatchType+    chooseType = \case+      [] -> SlbtUnknown+      xs | all isLambda xs -> SlbtLambda+      xs | all (not . isAddLambda) xs -> SlbtData+         | otherwise -> SlbtCustom++    isLambda :: DMigrationActionDesc -> Bool+    isLambda = \case { TLambda{} -> True; _ -> False } . manFieldType++    isAddLambda :: DMigrationActionDesc -> Bool+    isAddLambda a = and+      [ isLambda a+      , case manAction a of { DAddAction _ -> True; _ -> False }+      ]++-- | Similar to 'nub', counts number of invocations and attaches to text entry.+--+-- >>> nubCounting ["a", "b", "a"]+-- ["a (x2)", "b"]+nubCounting :: [Text] -> [Text]+nubCounting = \case+  [] -> []+  x : xs ->+    let ((length -> repetitions), others) = L.partition (== x) xs+        x' = if repetitions == 0+             then x+             else x <> " (x" <> show (repetitions + 1) <> ")"+    in x' : nubCounting others
+ src/Lorentz/UStore/Migration/Blocks.hs view
@@ -0,0 +1,287 @@+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++-- | Elemental building blocks for migrations.+module Lorentz.UStore.Migration.Blocks+  ( -- * General+    mustoreToOld+  , MigrationFinishCheckPosition (..)++    -- * Elemental steps+  , migrateCoerceUnsafe+  , migrateGetField+  , migrateAddField+  , migrateRemoveField+  , migrateExtractField+  , migrateOverwriteField+  , migrateModifyField++    -- * Migration batches+  , muBlock+  , muBlockNamed+  , (<-->)+  , ($:)+  ) where++import Data.Vinyl.Derived (Label)++import Lorentz.Base+import Lorentz.Coercions+import Lorentz.Instr (dip)+import Lorentz.UStore.Instr+import Lorentz.UStore.Migration.Base+import Lorentz.UStore.Migration.Diff+import Lorentz.UStore.Types+import Util.Type+import Util.TypeLits++-- | Helper for 'mustoreToOld' which ensures that given store hasn't been+-- (partially) migrated yet.+type family RequireBeInitial (touched :: [Symbol]) :: Constraint where+  RequireBeInitial '[] = ()+  RequireBeInitial _ =+    TypeError ('Text "Migration has already been started over this store")++type family RequireUntouched (field :: Symbol) (wasTouched :: Bool)+             :: Constraint where+  RequireUntouched _ 'False = ()+  RequireUntouched field 'True = TypeError+    ('Text ("Field `" `AppendSymbol` field `AppendSymbol` "` has already been \+            \migrated and cannot be read")+    )++-- | Cast field or submap pretending that its value fits to the new type.+--+-- Useful when type of field, e.g. lambda or set of lambdas, is polymorphic+-- over storage type.+migrateCoerceUnsafe+  :: forall field oldTempl newTempl diff touched newDiff newDiff0 _1 _2 s.+     ( '(_1, newDiff0) ~ CoverDiff 'DcRemove field diff+     , '(_2, newDiff) ~ CoverDiff 'DcAdd field newDiff0+     )+  => Label field+  -> MUStore oldTempl newTempl diff touched : s+  :-> MUStore oldTempl newTempl newDiff touched : s+migrateCoerceUnsafe _ =+  coerce_++-- Migrating fields+----------------------------------------------------------------------------++-- | Get a field present in old version of 'UStore'.+migrateGetField+  :: forall field oldTempl newTempl diff touched fieldTy s.+     ( HasUField field fieldTy oldTempl+     , RequireUntouched field (field `IsElem` touched)+     )+  => Label field+  -> MUStore oldTempl newTempl diff touched : s+  :-> fieldTy : MUStore oldTempl newTempl diff touched : s+migrateGetField label =+  coerce_ @_ @(UStore oldTempl) # ustoreGetField label # dip coerce_++-- | Add a field which was not present before.+-- This covers one addition from the diff and any removals of field with given+-- name.+--+-- This function cannot overwrite existing field with the same name, if this+-- is necessary use 'migrateOverwriteField' which would declare removal+-- explicitly.+migrateAddField+  :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s.+     ( '(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcAdd field diff+     , HasUField field fieldTy newTempl+     )+  => Label field+  -> fieldTy : MUStore oldTempl newTempl diff touched : s+  :-> MUStore oldTempl newTempl newDiff (field ': touched) : s+migrateAddField label =+  attachMigrationActionName (DAddAction "add") label (Proxy @fieldTy) #+  dip (coerce_ @_ @(UStore newTempl)) # ustoreSetField label # coerce_++-- | Remove a field which should not be present in new version of storage.+-- This covers one removal from the diff.+--+-- In fact, this action could be performed automatically, but since+-- removal is a destructive operation, being explicit about it seems+-- like a good thing.+migrateRemoveField+  :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s.+     ( '(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcRemove field diff+     , HasUField field fieldTy oldTempl+     )+  => Label field+  -> MUStore oldTempl newTempl diff touched : s+  :-> MUStore oldTempl newTempl newDiff (field ': touched) : s+migrateRemoveField label =+  attachMigrationActionName DDelAction label (Proxy @fieldTy) #+  coerce_ @_ @(UStore oldTempl) # ustoreRemoveFieldUnsafe label # coerce_++-- | Get and remove a field from old version of 'UStore'.+--+-- You probably want to use this more often than plain 'migrateRemoveField'.+migrateExtractField+  :: forall field oldTempl newTempl diff touched fieldTy newDiff marker s.+     ( '(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcRemove field diff+     , HasUField field fieldTy oldTempl+     , RequireUntouched field (field `IsElem` touched)+     )+  => Label field+  -> MUStore oldTempl newTempl diff touched : s+  :-> fieldTy : MUStore oldTempl newTempl newDiff (field ': touched) : s+migrateExtractField label =+  attachMigrationActionName DDelAction label (Proxy @fieldTy) #+  migrateGetField label # dip (migrateRemoveField label)++-- | Remove field and write new one in place of it.+--+-- This is semantically equivalent to+-- @dip (migrateRemoveField label) >> migrateAddField label@,+-- but is cheaper.+migrateOverwriteField+  :: forall field oldTempl newTempl diff touched fieldTy oldFieldTy+            marker oldMarker newDiff newDiff0 s.+     ( '(UStoreFieldExt oldMarker oldFieldTy, newDiff0) ~ CoverDiff 'DcRemove field diff+     , '(UStoreFieldExt marker fieldTy, newDiff) ~ CoverDiff 'DcAdd field newDiff0+     , HasUField field fieldTy newTempl+     )+  => Label field+  -> fieldTy : MUStore oldTempl newTempl diff touched : s+  :-> MUStore oldTempl newTempl newDiff (field ': touched) : s+migrateOverwriteField label =+  attachMigrationActionName (DAddAction "overwrite") label (Proxy @fieldTy) #+  dip (coerce_ @_ @(UStore newTempl)) # ustoreSetField label # coerce_++-- | Modify field which should stay in new version of storage.+-- This does not affect remaining diff.+migrateModifyField+  :: forall field oldTempl newTempl diff touched fieldTy s.+     ( HasUField field fieldTy oldTempl+     , HasUField field fieldTy newTempl+     )+  => Label field+  -> fieldTy : MUStore oldTempl newTempl diff touched : s+  :-> MUStore oldTempl newTempl diff touched : s+migrateModifyField label =+  attachMigrationActionName (DAddAction "modify") label (Proxy @fieldTy) #+  dip (coerce_ @_ @(UStore oldTempl)) # ustoreSetField label # coerce_++-- Migrating virtual submaps (strict migration)+----------------------------------------------------------------------------++{- For now we do not support this kind of migration.++"Strict" means that we want to modify maps right here rather than signal to+do modification of each entry on first access to it (which would be simpler+in some sense).++Implementing this is slightly less trivial than migrating individial fields.+1. One needs current value of UStore picked from the contract, because it's+not possible to iterate over big_map from within a contract in the current mainnet.+Even if it was, we can't assume that iteration of the whole submap would fit+into gas limit of single transaction, thus iteration should be performed+from outside of the contract by someone who knows the current storage.++2. We need to split migration in batches smartly. Too big batches would hit+operation size limit, while small ones would cause high overhead of+contract/storage deserialization.+Will be resolved in TM-330.+-}++----------------------------------------------------------------------------+-- Blocks for batched migrations+----------------------------------------------------------------------------++-- | Define a migration atom.+--+-- It will be named automatically according to the set of actions it performs+-- (via 'DMigrationActionDesc's).+-- This may be want you want for small sequences of actions, but for complex ones+-- consider using 'muBlockNamed'.+-- Names are used in rendering migration plan.+muBlock+  :: ('[MUStore o n d1 t1] :-> '[MUStore o n d2 t2])+  -> MigrationBlocks o n d1 t1 d2 t2+muBlock code =+  MigrationBlocks . one . formMigrationAtom Nothing $+    coerce_ # code # coerce_++-- | Define a migration atom with given name.+--+-- Name will be used when rendering migration plan.+muBlockNamed+  :: Text+  -> ('[MUStore o n d1 t1] :-> '[MUStore o n d2 t2])+  -> MigrationBlocks o n d1 t1 d2 t2+muBlockNamed name code =+  MigrationBlocks . one . formMigrationAtom (Just name) $+    coerce_ # code # coerce_++-- | Composition of migration blocks.+(<-->)+  :: MigrationBlocks o n d1 t1 d2 t2+  -> MigrationBlocks o n d2 t2 d3 t3+  -> MigrationBlocks o n d1 t1 d3 t3+MigrationBlocks blocks1 <--> MigrationBlocks blocks2 =+  MigrationBlocks (blocks1 <> blocks2)+infixl 2 <-->++{- | This is '$' operator with priority higher than '<-->'.++It allows you writing++@+mkUStoreBatchedMigration =+  muBlock $: do+    migrateAddField ...+  <-->+  muBlock $: do+    migrateRemoveField ...+@++Alternatively, @BlockArguments@ extension can be used.+-}+($:) :: (a -> b) -> a -> b+($:) = ($)+infixr 7 $:++----------------------------------------------------------------------------+-- Common+----------------------------------------------------------------------------++-- | Get the old version of storage.+--+-- This can be applied only in the beginning of migration.+--+-- In fact this function is not very useful, all required operations should+-- be available for 'MUStore', but leaving it here just in case.+mustoreToOld+  :: RequireBeInitial touched+  => MUStore oldTemplate newTemplate remDiff touched : s+  :-> UStore oldTemplate : s+mustoreToOld = coerce_++class MigrationFinishCheckPosition a where+  -- | Put this in the end of migration script to get a human-readable message+  -- about remaining diff which yet should be covered.+  -- Use of this function in migration is fully optional.+  --+  -- This function is not part of 'mkUStoreMigration' for the sake of+  -- proper error messages ordering, during development+  -- you probably want errors in migration script to be located earlier+  -- in code than errors about not fully covered diff (if you used+  -- to fix errors in the same order in which they appear).+  migrationFinish :: a++-- | This version can be used in 'mkUStoreMigration'.+instance ( i ~ (MUStore oldTempl newTempl diff touched : s)+         , o ~ (MUStore oldTempl newTempl '[] touched : s)+         , RequireEmptyDiff diff+         ) =>+         MigrationFinishCheckPosition (i :-> o) where+  migrationFinish = coerce_++-- | This version can be used in 'mkUStoreMultiMigration' as the last migration+-- block.+instance (RequireEmptyDiff d1, t1 ~ t2) =>+         MigrationFinishCheckPosition (MigrationBlocks o n d1 t1 '[] t2) where+  migrationFinish = MigrationBlocks []
+ src/Lorentz/UStore/Migration/Diff.hs view
@@ -0,0 +1,196 @@+module Lorentz.UStore.Migration.Diff+  ( FieldInfo+  , DiffKind (..)+  , DiffItem+  , BuildDiff+  , ShowDiff+  , RequireEmptyDiff++  , LinearizeUStore+  , LinearizeUStoreF+  , AllUStoreFieldsF++  , DiffCoverage (..)+  , CoverDiff+  , CoverDiffMany+  ) where++import qualified Data.Kind as Kind+import GHC.Generics ((:*:), (:+:))+import Fcf (Eval, Exp, Pure, Fst, type (=<<), type (***))+import qualified Fcf+import Fcf.Data.List (Cons)+import Fcf.Utils (TError)+import qualified GHC.Generics as G++import Lorentz.UStore.Types+import Util.Type+import Util.TypeLits++-- Diff definition+----------------------------------------------------------------------------++-- | Information about single field of UStore.+type FieldInfo = (Symbol, Kind.Type)++-- | What should happen with a particular 'UStoreItem'.+data DiffKind = ToAdd | ToDel++-- | Single piece of a diff.+type DiffItem = (DiffKind, FieldInfo)++-- Building diff+----------------------------------------------------------------------------++-- | Get information about all fields of UStore template in a list.+--+-- In particular, this recursivelly traverses template and retrives+-- names and types of fields. Semantic wrappers like 'UStoreField'+-- and '|~>' in field types are returned as-is.+type LinearizeUStore a = GLinearizeUStore (G.Rep a)++data LinearizeUStoreF (template :: Kind.Type) :: Exp [FieldInfo]+type instance Eval (LinearizeUStoreF template) = LinearizeUStore template++-- | Get only field names of UStore template.+type family AllUStoreFieldsF (template :: Kind.Type) :: Exp [Symbol] where+  AllUStoreFieldsF template = Fcf.Map Fst =<< LinearizeUStoreF template++type family GLinearizeUStore (template :: Kind.Type -> Kind.Type)+    :: [FieldInfo] where+  GLinearizeUStore (G.D1 _ x) = GLinearizeUStore x+  GLinearizeUStore (G.C1 _ x) = GLinearizeUStore x+  GLinearizeUStore (_ :+: _) = TypeError+    ('Text "Unexpected sum type in UStore template")+  GLinearizeUStore G.V1 = TypeError+    ('Text "Unexpected void-like type in UStore template")+  GLinearizeUStore G.U1 = '[]+  GLinearizeUStore (x :*: y) = GLinearizeUStore x ++ GLinearizeUStore y++  GLinearizeUStore (G.S1 ('G.MetaSel mfield _ _ _) (G.Rec0 (k |~> v))) =+    '[ '(RequireFieldName mfield, k |~> v) ]+  GLinearizeUStore (G.S1 ('G.MetaSel mfield _ _ _) (G.Rec0 (UStoreFieldExt m v))) =+    '[ '(RequireFieldName mfield, UStoreFieldExt m v) ]+  GLinearizeUStore (G.S1 _ (G.Rec0 a)) =+    LinearizeUStore a++-- | Helper to make sure that datatype field is named and then extract this name.+type family RequireFieldName (mfield :: Maybe Symbol) :: Symbol where+  RequireFieldName ('Just field) = field+  RequireFieldName 'Nothing = TypeError ('Text "Unnamed field in UStore template")++-- | Lift a list of 'FieldInfo' to 'DiffItem's via attaching given 'DiffKind'.+type family LiftToDiff (kind :: DiffKind) (items :: [FieldInfo]) :: [DiffItem] where+  LiftToDiff _ '[] = '[]+  LiftToDiff kind (item ': items) = '(kind, item) ': LiftToDiff kind items++-- | Make up a migration diff between given old and new 'UStore' templates.+type BuildDiff oldTemplate newTemplate =+  LiftToDiff 'ToAdd (LinearizeUStore newTemplate // LinearizeUStore oldTemplate)+  +++  LiftToDiff 'ToDel (LinearizeUStore oldTemplate // LinearizeUStore newTemplate)++-- Pretty-printing diff+----------------------------------------------------------------------------++-- | Renders human-readable message describing given diff.+type ShowDiff diff =+  'Text "Migration is incomplete, remaining diff:" ':$$: ShowDiffItems diff++type family ShowDiffItems (diff :: [DiffItem]) :: ErrorMessage where+  ShowDiffItems '[d] = ShowDiffItem d+  ShowDiffItems (d : ds) = ShowDiffItem d ':$$: ShowDiffItems ds++type family ShowDiffKind (kind :: DiffKind) :: Symbol where+  ShowDiffKind 'ToAdd = "+"+  ShowDiffKind 'ToDel = "-"++type family ShowUStoreElement (ty :: Kind.Type) :: ErrorMessage where+  ShowUStoreElement (UStoreFieldExt m f) =+    ShowUStoreField m f+  ShowUStoreElement (k |~> v) =+    'Text "submap " ':<>: 'ShowType k ':<>: 'Text " -> " ':<>: 'ShowType v++type family ShowDiffItem (diff :: DiffItem) :: ErrorMessage where+  ShowDiffItem '(kind, '(field, ty)) =+    'Text (ShowDiffKind kind `AppendSymbol`+           " `" `AppendSymbol`+           field `AppendSymbol`+           "`") ':<>:+    'Text ": " ':<>: ShowUStoreElement ty++-- | Helper type family which dumps error message about remaining diff+-- if such is present.+type family RequireEmptyDiff (diff :: [DiffItem]) :: Constraint where+  RequireEmptyDiff '[] = ()+  RequireEmptyDiff diff = TypeError (ShowDiff diff)++-- Diff coverage+----------------------------------------------------------------------------++-- | Cover the respective part of diff.+-- Maybe fail if such action is not required.+--+-- This type is very similar to 'DiffKind', but we still use another type as+-- 1. Their kinds will differ - no chance to mix up anything.+-- 2. One day there might appear more complex actions.+data DiffCoverage+  = DcAdd+  | DcRemove++type family PrefixSecond (a :: k2) (r :: (k1, [k2])) :: (k1, [k2]) where+  PrefixSecond a '(t, l) = '(t, (a ': l))++-- | Apply given diff coverage, returning type of affected field and modified+-- diff.+type family CoverDiff (cover :: DiffCoverage) (field :: Symbol) (diff :: [DiffItem])+            :: (Kind.Type, [DiffItem]) where+  CoverDiff cover field diff = Eval (CoverDiffF '(cover, field) diff)++type family CoverDiffF (arg :: (DiffCoverage, Symbol)) (diff :: [DiffItem])+            :: Exp (Kind.Type, [DiffItem]) where+  CoverDiffF '( 'DcAdd, field) diff = RemoveDiffF 'ToAdd field diff+  CoverDiffF '( 'DcRemove, field) diff = RemoveDiffF 'ToDel field diff++type family RemoveDiffF (kind :: DiffKind) (field :: Symbol) (diff :: [DiffItem])+            :: Exp (Kind.Type, [DiffItem]) where+  RemoveDiffF kind field ('(kind, '(field, ty)) ': diff) = Pure '(ty, diff)+  RemoveDiffF kind field (d ': diff) = (Pure *** Cons d) =<< RemoveDiffF kind field diff+  RemoveDiffF kind field '[] =+    TError ('Text (ShowDiffKindWord kind) ':<>: 'Text " field " ':<>:+            'ShowType field ':<>: 'Text " is not required")++type family ShowDiffKindWord (kind :: DiffKind) :: Symbol where+  ShowDiffKindWord 'ToAdd = "Adding"+  ShowDiffKindWord 'ToDel = "Removing"++-- | Single piece of a coverage.+type DiffCoverageItem = (DiffCoverage, FieldInfo)++-- | Apply multiple coverage steps.+type family CoverDiffMany (diff :: [DiffItem]) (covers :: [DiffCoverageItem])+            :: [DiffItem] where+  CoverDiffMany diff '[] = diff+  CoverDiffMany diff ('(dc, '(field, ty)) ': cs) =+    CoverDiffMany (HandleCoverRes field ty (CoverDiff dc field diff)) cs++type family HandleCoverRes (field :: Symbol) (ty :: Kind.Type) (res :: (Kind.Type, [DiffItem]))+            :: [DiffItem] where+  HandleCoverRes _ ty '(ty, diff) = diff+  HandleCoverRes field tyCover '(tyDiff, _) = TypeError+    ('Text "Type mismatch when covering diff for field " ':<>: 'ShowType field+     ':$$:+     'Text "Expected type `" ':<>: 'ShowType tyDiff ':<>: 'Text "` (in requested diff)"+     ':$$:+     'Text "but covered with value of type `" ':<>: 'ShowType tyCover ':<>: 'Text "`"+    )++type family EnsureDiffHasNoRemovalF (field :: Symbol) (diff :: [DiffItem])+             :: Exp [DiffItem] where+  EnsureDiffHasNoRemovalF _ '[] = Pure '[]+  EnsureDiffHasNoRemovalF field ('( 'ToDel, '(field, _)) ': _) =+    TError ('Text "Field with name " ':<>: 'ShowType field ':<>:+            'Text " is present in old version of storage"+           )+  EnsureDiffHasNoRemovalF field (d ': diff) =+    Cons d =<< EnsureDiffHasNoRemovalF field diff
+ src/Lorentz/UStore/Types.hs view
@@ -0,0 +1,261 @@+{-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}++-- | 'UStore' definition and common type-level stuff.+module Lorentz.UStore.Types+  ( -- * UStore and related type definitions+    UStore (..)+  , type (|~>)(..)+  , UStoreFieldExt (..)+  , UStoreField+  , UStoreMarkerType+  , UMarkerPlainField++    -- ** Extras+  , KnownUStoreMarker (..)+  , mkFieldUKey++    -- ** Type-lookup-by-name+  , GetUStoreKey+  , GetUStoreValue+  , GetUStoreField+  , GetUStoreFieldMarker++    -- ** Marked fields+  , PickMarkedFields++   -- * Internals+  , ElemSignature (..)+  , GetUStore+  , MSKey+  , MSValue+  , FSValue+  , FSMarker+  ) where++import Data.Default (Default)+import Data.Vinyl.Derived (Label)+import qualified Data.Kind as Kind+import Data.Type.Equality (type (==))+import GHC.Generics ((:*:)(..), (:+:)(..))+import qualified GHC.Generics as G+import GHC.TypeLits (ErrorMessage(..), Symbol, TypeError, KnownSymbol)++import Lorentz.Pack+import Lorentz.Doc+import Lorentz.Polymorphic+import Michelson.Typed.Haskell.Value+import Lorentz.UStore.Common+import Util.Type++-- | Gathers multple fields and 'BigMap's under one object.+--+-- Type argument of this datatype stands for a "store template" -+-- a datatype with one constructor and multiple fields, each containing+-- an object of type 'UStoreField' or '|~>' and corresponding to single+-- virtual field or 'BigMap' respectively.+-- It's also possible to parameterize it with a larger type which is+-- a product of types satisfying the above property.+newtype UStore (a :: Kind.Type) = UStore+  { unUStore :: BigMap ByteString ByteString+  } deriving stock (Eq, Show, Generic)+    deriving newtype (Default, Semigroup, Monoid, IsoValue,+                      MemOpHs, GetOpHs, UpdOpHs)++-- | Describes one virtual big map in the storage.+newtype k |~> v = UStoreSubMap { unUStoreSubMap :: Map k v }+  deriving stock (Show, Eq)+  deriving newtype (Default)++-- | Describes plain field in the storage.+newtype UStoreFieldExt (m :: UStoreMarkerType) (v :: Kind.Type) = UStoreField { unUStoreField :: v }+  deriving stock (Show, Eq)++-- | Just a servant type.+data UStoreMarker++-- | Specific kind used to designate markers for 'UStoreFieldExt'.+--+-- We suggest that fields may serve different purposes and so annotated with+-- special markers accordingly. See example below.+--+-- This kind is implemented like that because we want markers to differ from all+-- other types in kind; herewith 'UStoreMarkerType' is still an open kind+-- (has potentially infinite number of inhabitants).+type UStoreMarkerType = UStoreMarker -> Kind.Type++-- | Just a plain field used as data.+type UStoreField = UStoreFieldExt UMarkerPlainField+data UMarkerPlainField :: UStoreMarkerType++instance Typeable template => TypeHasDoc (UStore template) where+  typeDocName _ = "Upgradeable storage"+  typeDocMdDescription =+    "Storage with not hardcoded structure, which allows upgrading the contract \+    \in place."+  typeDocMdReference tp =+    customTypeDocMdReference ("UStore", DType tp) []+  typeDocHaskellRep = homomorphicTypeDocHaskellRep+  typeDocMichelsonRep = homomorphicTypeDocMichelsonRep++-- Extra attributes of fields+----------------------------------------------------------------------------++-- | Allows to specify format of key under which fields of this type are stored.+-- Useful to avoid collisions.+class KnownUStoreMarker (marker :: UStoreMarkerType) where+  -- | By field name derive key under which field should be stored.+  mkFieldMarkerUKey :: KnownSymbol name => Label name -> ByteString+  default mkFieldMarkerUKey :: KnownSymbol name => Label name -> ByteString+  mkFieldMarkerUKey (_ :: Label field) = lPackValue $ fieldNameToMText @field++  -- | Display type-level information about UStore field with given marker and+  -- field value type.+  -- Used for error messages.+  type ShowUStoreField marker v :: ErrorMessage+  type ShowUStoreField marker v = 'Text "field of type " ':<>: 'ShowType v++-- | Shortcut for 'mkFieldMarkerUKey' which accepts not marker but store type and+-- name of entry.+mkFieldUKey+  :: forall (store :: Kind.Type) name.+     (KnownSymbol name, KnownUStoreMarker (GetUStoreFieldMarker store name))+  => Label name -> ByteString+mkFieldUKey = mkFieldMarkerUKey @(GetUStoreFieldMarker store name)++instance KnownUStoreMarker UMarkerPlainField where++----------------------------------------------------------------------------+-- Type-safe lookup magic+----------------------------------------------------------------------------++{- Again we use generic magic to implement methods for 'Store'+(and thus 'Store' type constructor accepts a datatype, not a type-level list).++There are two reasons for this:++1. This gives us expected balanced tree of 'Or's for free.++2. This allows us selecting a map by field name, not by+e.g. type of map value. This is subjective, but looks like a good thing+for me (@martoon). On the other hand, it prevents us from sharing the+same interface between maps and 'Store'.++-}++-- | What was found on lookup by constructor name.+--+-- This keeps either type arguments of '|~>' or 'UStoreField'.+data ElemSignature+  = MapSignature Kind.Type Kind.Type+  | FieldSignature UStoreMarkerType Kind.Type++-- Again, we will use these getters instead of binding types within+-- 'MapSignature' using type equality because getters does not produce extra+-- compile errors on "field not found" cases.+type family MSKey (ms :: ElemSignature) :: Kind.Type where+  MSKey ('MapSignature k _) = k+  MSKey ('FieldSignature _ _) =+    TypeError ('Text "Expected UStore submap, but field was referred")+type family MSValue (ms :: ElemSignature) :: Kind.Type where+  MSValue ('MapSignature _ v) = v+  MSValue ('FieldSignature _ _) =+    TypeError ('Text "Expected UStore submap, but field was referred")+type family FSValue (ms :: ElemSignature) :: Kind.Type where+  FSValue ('FieldSignature _ v) = v+  FSValue ('MapSignature _ _) =+    TypeError ('Text "Expected UStore field, but submap was referred")+type family FSMarker (ms :: ElemSignature) :: UStoreMarkerType where+  FSValue ('FieldSignature m _) = m+  FSValue ('MapSignature _ _) =+    TypeError ('Text "Expected UStore field, but submap was referred")++-- | Get map signature from the constructor with a given name.+type GetUStore name a = MERequireFound name a (GLookupStore name (G.Rep a))++type family MERequireFound+  (name :: Symbol)+  (a :: Kind.Type)+  (mlr :: Maybe ElemSignature)+    :: ElemSignature where+  MERequireFound _ _ ('Just ms) = ms+  MERequireFound name a 'Nothing = TypeError+    ('Text "Failed to find plain field or submap in store template: datatype `"+     ':<>: 'ShowType a ':<>: 'Text "` has no field " ':<>: 'ShowType name)++type family GLookupStore (name :: Symbol) (x :: Kind.Type -> Kind.Type)+              :: Maybe ElemSignature where+  GLookupStore name (G.D1 _ x) = GLookupStore name x+  GLookupStore _ (_ :+: _) =+    TypeError ('Text "Templates used in UStore should have only one constructor")+  GLookupStore _ G.V1 =+    TypeError ('Text "No constructors in UStore template")++  GLookupStore name (G.C1 _ x) = GLookupStore name x++  GLookupStore name (x :*: y) = LSMergeFound name (GLookupStore name x)+                                                  (GLookupStore name y)++  -- When we encounter a field there are three cases we are interested in:+  -- 1. This field has type '|~>'. Then we check its name and return 'Just'+  -- with all required info on match, and 'Nothing' otherwise.+  -- 2. This field has type 'UStoreField'. We act in the same way+  -- as for '|~>', attaching 'ThePlainFieldKey' as key.+  -- 3. This field type is a different one. Then we expect this field to store+  -- '|~>' or 'UStoreField' somewhere deeper and try to find it there.+  GLookupStore name (G.S1 ('G.MetaSel mFieldName _ _ _) (G.Rec0 (k |~> v))) =+    Guard ('Just name == mFieldName) ('MapSignature k v)+  GLookupStore name (G.S1 ('G.MetaSel mFieldName _ _ _) (G.Rec0 (UStoreFieldExt m v))) =+    Guard ('Just name == mFieldName) ('FieldSignature m v)++  GLookupStore name (G.S1 _ (G.Rec0 a)) =+    GLookupStore name (G.Rep a)++  GLookupStore _ G.U1 = 'Nothing++type family LSMergeFound (name :: Symbol)+  (f1 :: Maybe ElemSignature) (f2 :: Maybe ElemSignature)+  :: Maybe ElemSignature where+  LSMergeFound _ 'Nothing 'Nothing = 'Nothing+  LSMergeFound _ ('Just ms) 'Nothing = 'Just ms+  LSMergeFound _ 'Nothing ('Just ms) = 'Just ms+  -- It's possible that there are two constructors with the same name,+  -- because main template pattern may be a sum of smaller template+  -- patterns with same constructor names.+  LSMergeFound ctor ('Just _) ('Just _) = TypeError+    ('Text "Found more than one constructor matching " ':<>: 'ShowType ctor)+++-- | Get type of submap key.+type GetUStoreKey store name = MSKey (GetUStore name store)++-- | Get type of submap value.+type GetUStoreValue store name = MSValue (GetUStore name store)++-- | Get type of plain field.+-- This ignores marker with field type.+type GetUStoreField store name = FSValue (GetUStore name store)++-- | Get kind of field.+type GetUStoreFieldMarker store name = FSMarker (GetUStore name store)++-- One more magic+----------------------------------------------------------------------------++-- | Collect all fields with the given marker.+type PickMarkedFields marker template = GPickMarkedFields marker (G.Rep template)++type family GPickMarkedFields (marker :: UStoreMarkerType) (x :: Kind.Type -> Kind.Type)+             :: [(Symbol, Kind.Type)] where+  GPickMarkedFields m (G.D1 _ x) = GPickMarkedFields m x+  GPickMarkedFields m (G.C1 _ x) = GPickMarkedFields m x+  GPickMarkedFields m (x :*: y) = GPickMarkedFields m x ++ GPickMarkedFields m y+  GPickMarkedFields _ G.U1 = '[]++  GPickMarkedFields m (G.S1 ('G.MetaSel ('Just fieldName) _ _ _) (G.Rec0 (UStoreFieldExt m v))) =+    '[ '(fieldName, v) ]+  GPickMarkedFields _ (G.S1 _ (G.Rec0 (UStoreFieldExt _ _))) =+    '[]+  GPickMarkedFields _ (G.S1 _ (G.Rec0 (_ |~> _))) =+    '[]+  GPickMarkedFields m (G.S1 _ (G.Rec0 a)) =+    PickMarkedFields m a
src/Lorentz/Value.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}+ -- | Re-exports typed Value, CValue, some core types, some helpers and -- defines aliases for constructors of typed values. @@ -6,14 +8,18 @@   , IsoValue (..)   , IsoCValue (..)   , CValue (..)++    -- * Primitive types   , Integer   , Natural   , MText   , Bool (..)   , ByteString   , Address+  , EpAddress (..)   , Mutez   , Timestamp+  , ChainId   , KeyHash   , PublicKey   , Signature@@ -23,20 +29,127 @@   , M.Operation   , Maybe (..)   , List-  , M.ContractAddr (..)+  , ContractRef (..)+  , FutureContract (..)++  , EntryPointCall+  , SomeEntryPointCall++    -- * Constructors   , toMutez   , mt+  , timestampFromSeconds+  , timestampFromUTCTime+  , timestampQuote++    -- * Conversions+  , M.coerceContractRef+  , embodyFutureContract+  , ToAddress (..)+  , ToContractRef (..)+  , FromContractRef (..)+  , convertContractRef++    -- * Misc   , Default (..)   ) where  import Data.Default (Default(..))+import Data.Kind as Kind +import Lorentz.Constraints import Michelson.Text-import Michelson.Typed (IsoCValue(..), IsoValue(..), Value)+import Michelson.Typed+  (ContractRef(..), EntryPointCall, IsoCValue(..), IsoValue(..), SomeEntryPointCall, Value) import qualified Michelson.Typed as M import Michelson.Typed.CValue (CValue(..))+import Michelson.Typed.EntryPoints (EpAddress(..)) import Tezos.Address (Address)-import Tezos.Core (Mutez, Timestamp, toMutez)+import Tezos.Core+  (ChainId, Mutez, Timestamp, timestampFromSeconds, timestampFromUTCTime, timestampQuote, toMutez) import Tezos.Crypto (KeyHash, PublicKey, Signature)  type List = []++-- | Address associated with the contract of given type.+--+-- Places where 'ContractAddr' can appear are now severely limited,+-- this type gives you type-safety of 'ContractAddr' but still can be used everywhere.+--+-- This may be refer to specific entrypoint of the contract, in such case+-- type parameter @p@ stands for argument of that entrypoint like in+-- 'ContractAddr'.+--+-- You still cannot be sure that the referred contract exists though.+newtype FutureContract p = FutureContract { futureContractAddress :: EpAddress }+  deriving stock Generic+  deriving anyclass IsoValue++-- | Turn future contract into actual @contract@.+embodyFutureContract+  :: forall arg.+     (NiceParameter arg, HasCallStack)+  => FutureContract arg -> ContractRef arg+embodyFutureContract (FutureContract (EpAddress addr M.NoEpName)) =+  withDict (niceParameterEvi @arg) $ ContractRef addr def+embodyFutureContract _ =+  -- TODO [TM-280]: implement+  error "not implemented for specific entrypoints"++-- | Convert something to 'Address' in /Haskell/ world.+--+-- Use this when you want to access state of the contract and are not interested+-- in calling it.+class ToAddress a where+  toAddress :: a -> Address++instance ToAddress Address where+  toAddress = id++instance ToAddress EpAddress where+  toAddress = eaAddress++instance ToAddress (FutureContract cp) where+  toAddress = toAddress . futureContractAddress++instance ToAddress (ContractRef cp) where+  toAddress = crAddress++-- | Convert something to 'ContractRef' in /Haskell/ world.+class ToContractRef (cp :: Kind.Type) (contract :: Kind.Type) where+  toContractRef :: HasCallStack => contract -> ContractRef cp++instance (cp ~ cp') => ToContractRef cp (ContractRef cp') where+  toContractRef = id++instance (NiceParameter cp, cp ~ cp') => ToContractRef cp (FutureContract cp') where+  toContractRef = embodyFutureContract++instance (NiceParameter cp) => ToContractRef cp EpAddress where+  toContractRef = embodyFutureContract . FutureContract++-- | Make contract ref calling the default entrypoint.+instance (NiceParameter cp) => ToContractRef cp Address where+  toContractRef addr = toContractRef $ EpAddress addr def++-- | Convert something from 'ContractAddr' in /Haskell/ world.+class FromContractRef (cp :: Kind.Type) (contract :: Kind.Type) where+  fromContractAddr :: ContractRef cp -> contract++instance (cp ~ cp') => FromContractRef cp (ContractRef cp') where+  fromContractAddr = id++instance (cp ~ cp') => FromContractRef cp (FutureContract cp') where+  fromContractAddr = FutureContract . fromContractAddr++instance FromContractRef cp EpAddress where+  fromContractAddr (ContractRef addr sepc) = EpAddress addr (M.sepcName sepc)++instance FromContractRef cp Address where+  fromContractAddr = eaAddress . fromContractAddr++convertContractRef+  :: forall cp contract2 contract1.+     (ToContractRef cp contract1, FromContractRef cp contract2)+  => contract1 -> contract2+convertContractRef = fromContractAddr @cp . toContractRef
+ src/Lorentz/Zip.hs view
@@ -0,0 +1,82 @@+{-# OPTIONS_GHC -Wno-orphans #-}++-- | Stack zipping.+--+-- This module provides functions for flattening stacks into tuples.+--+-- Also here we define an instance which turns any instruction,+-- not only lambdas, into a valid value.+module Lorentz.Zip+  ( ZipInstr (..)+  , ZipInstrs+  , zippingStack+  , unzippingStack+  ) where++import Prelude hiding (drop)++import qualified Data.Kind as Kind++import Lorentz.Base+import Michelson.Typed++-- | Zipping stack into tuple and back.+class ZipInstr (s :: [Kind.Type]) where+  -- | A type which contains the whole stack zipped.+  type ZippedStack s :: Kind.Type++  -- | Fold given stack into single value.+  zipInstr :: s :-> '[ZippedStack s]++  -- | Unfold given stack from a single value.+  unzipInstr :: '[ZippedStack s] :-> s++{- Further we have to work on low level because even "Lorentz.Instr" depends+   on this module.+-}++-- | Version of '#' which performs some optimizations immediatelly.+-- Need it here at least because we don't want to surround+-- @fromVal (Lambda i o)@ with nops.+(##) :: (a :-> b) -> (b :-> c) -> (a :-> c)+l ## r = case (l, r) of+  (I Nop, I x) -> I x+  (I x, I Nop) -> I x+  _ -> l # r++instance ZipInstr '[] where+  type ZippedStack '[] = ()+  zipInstr = I UNIT+  unzipInstr = I DROP++instance ZipInstr '[a] where+  type ZippedStack '[a] = a+  zipInstr = I Nop+  unzipInstr = I Nop++-- | Such definition seems the only possible one we can support+-- efficiently.+instance ZipInstr ((a, b) ': s) => ZipInstr (a ': b ': s) where+  type ZippedStack (a ': b ': s) = ZippedStack ((a, b) ': s)+  zipInstr = I PAIR ## zipInstr @((a, b) ': s)+  unzipInstr = unzipInstr @((a, b) ': s) ## I (DUP `Seq` CAR `Seq` DIP CDR)++-- | Require several stacks to comply 'ZipInstr' constraint.+type ZipInstrs ss = Each '[ZipInstr] ss++-- | Flatten both ends of instruction stack.+zippingStack+  :: ZipInstrs [inp, out]+  => inp :-> out -> Lambda (ZippedStack inp) (ZippedStack out)+zippingStack code = unzipInstr ## code ## zipInstr++-- | Unflatten both ends of instruction stack.+unzippingStack+  :: ZipInstrs [inp, out]+  => Lambda (ZippedStack inp) (ZippedStack out) -> inp :-> out+unzippingStack code = zipInstr ## code ## unzipInstr++instance (ZipInstr inp, ZipInstr out) => IsoValue (inp :-> out) where+  type ToT (inp :-> out) = 'TLambda (ToT (ZippedStack inp)) (ToT (ZippedStack out))+  toVal i = VLam . unLorentzInstr $ zippingStack i+  fromVal (VLam i) = zipInstr ## LorentzInstr i ## unzipInstr
+ src/Michelson/Analyzer.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE DerivingStrategies #-}++-- | Static analysis of Michelson code.++module Michelson.Analyzer+  ( AnalyzerRes (..)+  , analyze+  ) where++import Data.Default (def)+import qualified Data.HashMap.Strict as HM+import qualified Data.List.NonEmpty as NE+import Fmt (Buildable(..), Builder, blockMapF', hexF, nameF, (+|))++import Michelson.FailPattern+import Michelson.Text (MText)+import Michelson.Typed++data AnalyzerRes = AnalyzerRes+  { arConstStrings :: !(HashMap MText Word)+  -- ^ All string constants and number of their occurrences.+  , arConstBytes :: !(HashMap ByteString Word)+  -- ^ All bytes constants and number of their occurrences.+  , arErrorTags :: !(HashMap MText Word)+  -- ^ Which strings are used as error tags and how many times.+  -- There is no notion of "error tag" in Michelson, so we use a heuristic+  -- to find out whether a string is an error tag. Specifically, we consider+  -- three patterns:+  -- 1. A constant string is pushed and then there is `FAILWITH` immediately.+  -- 2. A constant string is pushed, followed by `PAIR` instruction and then+  -- `FAILWITH`.+  -- 3. A constant pair is pushed where the first item is a string and then+  -- there is `FAILWITH.+  } deriving stock (Show, Eq)++instance Buildable AnalyzerRes where+  build (AnalyzerRes+    (toPairs -> constStrings)+    (toPairs -> constBytes)+    (toPairs -> errorTags)+    ) =+    nameF "String constants"+      (buildStrings $ sortByCount constStrings)+    +|+    nameF "Bytes constants"+      (buildBytes $ sortByCount constBytes)+    +|+    nameF "Error tags"+      (buildStrings $ sortByCount errorTags)+    +|+    longest "strings" constStrings buildStrings+    +|+    longest "bytes" constBytes buildBytes+    where+      inQuotes toBuilder x = "\"" <> toBuilder x <> "\""++      buildStrings = blockMapF' (inQuotes build) build+      buildBytes = blockMapF' (mappend "0x" . hexF) build++      sortByCount :: [(k, Word)] -> [(k, Word)]+      sortByCount = sortWith snd++      sortByLength :: Container k => [(k, Word)] -> [(k, Word)]+      sortByLength = sortWith (Down . length . fst)++      longest ::+        Container x =>+        Builder -> [(x, Word)] -> ([(x, Word)] -> Builder) -> Builder+      longest name items builder+        | length items > 6 =+          nameF ("Longest " <> name) $ builder $ take 4 $ sortByLength items+        | otherwise = mempty++instance Semigroup AnalyzerRes where+  ar1 <> ar2 = AnalyzerRes+    { arConstStrings = arConstStrings ar1 <+> arConstStrings ar2+    , arConstBytes = arConstBytes ar1 <+> arConstBytes ar2+    , arErrorTags = arErrorTags ar1 <+> arErrorTags ar2+    }+    where+      m1 <+> m2 = HM.unionWith (+) m1 m2++instance Monoid AnalyzerRes where+  mempty = AnalyzerRes+    { arConstStrings = mempty+    , arConstBytes = mempty+    , arErrorTags = mempty+    }++-- | Statically analyze an instruction. Typed representation is used+-- because it's easier to analyze. It means that we can't analyze+-- ill-typed contracts, but hopefully it's not a serious limitation.+analyze :: Instr inp out -> AnalyzerRes+analyze = dfsFoldInstr def{ dsGoToValues = True } step+  where+    step :: forall i o. Instr i o -> AnalyzerRes+    step i = analyzeConstants i <> analyzeErrorTags i++    countItems :: (Ord i, Hashable i) => [i] -> HashMap i Word+    countItems = HM.fromList . map f . NE.group . sort+      where+        f ne = (head ne, fromIntegral $ length ne)++    analyzeConstants :: forall i o. Instr i o -> AnalyzerRes+    analyzeConstants = \case+      PUSH v -> mempty+        { arConstStrings = countItems $ allAtomicValues isStringValue v+        , arConstBytes = countItems $ allAtomicValues isBytesValue v+        }+      _ -> mempty++    analyzeErrorTags :: forall i o. Instr i o -> AnalyzerRes+    analyzeErrorTags i+      | Just tfw <- isTypicalFailWith i =+          mempty { arErrorTags = one (typicalFailWithTag tfw, 1) }+      | otherwise = mempty
+ src/Michelson/Doc.hs view
@@ -0,0 +1,481 @@+{-# LANGUAGE DerivingStrategies, TypeFamilyDependencies, UndecidableSuperClasses #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++-- | Renderable documentation injected to contract code.+module Michelson.Doc+  ( DocItem (..)+  , docItemPosition+  , DocItemId (..)+  , DocItemPlacementKind (..)+  , DocItemRef (..)+  , DocSectionNameStyle (..)+  , SomeDocItem (..)+  , SomeDocDefinitionItem (..)+  , DocBlock+  , SubDoc (..)+  , ContractDoc (..)+  , DocGrouping+  , cdContentsL+  , cdDefinitionsL+  , cdDefinitionsSetL+  , cdDefinitionIdsL+  , subDocToMarkdown+  , someDocItemToBlock+  , contractDocToMarkdown+  , docGroupContent+  , docDefinitionRef++  , DName (..)+  , DDescription (..)+  , DVersion (..)+  , DGitRevision (..)+  , GitRepoSettings (..)+  , mkDGitRevision+  , morleyRepoSettings+  , DComment (..)+  ) where++import qualified Data.Map as M+import qualified Data.Map.Merge.Strict as M+import qualified Data.Set as S+import qualified Data.Text as T+import qualified Data.Text.Lazy as LT+import Data.Typeable (cast, typeRep)+import Development.GitRev (gitCommitDate, gitHash)+import Fmt (Buildable, build, fmt, (+|), (+||), (|+), (||+))+import GHC.TypeNats (Nat)+import qualified Language.Haskell.TH as TH+import qualified Text.Show++import Util.Instances ()+import Util.Lens+import Util.Markdown+import Util.Type+import Util.Typeable++-- | A piece of documentation describing one property of a thing,+-- be it a name or description of a contract, or an error throwable+-- by given endpoint.+--+-- Items of the same type appear close to each other in a rendered documentation+-- and form a /section/.+--+-- Doc items are later injected into a contract code via a dedicated nop-like+-- instruction. Normally doc items which belong to one section appear in+-- resulting doc in the same order in which they appeared in the contract.+--+-- While documentation framework grows, this typeclass acquires more and more+-- methods for fine tuning of existing rendering logic because we don't want+-- to break backward compatibility, hope one day we will make everything+-- concise :(+-- E.g. all rendering and reording stuff could be merged in one method, and+-- we could have several template implementations for it which would allow+-- user to specify only stuff relevant to his case.+class (Typeable d, DOrd d, KnownNat (DocItemPosition d)) => DocItem d where+  -- | Position of this item in the resulting documentation;+  -- the smaller the value, the higher the section with this element+  -- will be placed.+  --+  -- Documentation structure is not necessarily flat.+  -- If some doc item consolidates a whole documentation block within it,+  -- this block will have its own placement of items independent from outer parts+  -- of the doc.+  type DocItemPosition d = (pos :: Nat) | pos -> d++  -- | When multiple items of the same type belong to one section, how+  -- this section will be called.+  --+  -- If not provided, section will contain just untitled content.+  docItemSectionName :: Maybe Text++  -- | Description of a section.+  --+  -- Can be used to mention some common things about all elements of this section.+  -- Markdown syntax is permitted here.+  docItemSectionDescription :: Maybe Markdown+  docItemSectionDescription = Nothing++  -- | How to render section name.+  --+  -- Takes effect only if section name is set.+  docItemSectionNameStyle :: DocSectionNameStyle+  docItemSectionNameStyle = DocSectionNameBig++  -- | Defines where given doc item should be put. There are two options:+  -- 1. Inline right here (default behaviour);+  -- 2. Put into definitions section.+  --+  -- Note that we require all doc items with "in definitions" placement to+  -- have 'Eq' and 'Ord' instances which comply the following law:+  -- if two documentation items describe the same entity or property, they+  -- should be considered equal.+  type DocItemPlacement d :: DocItemPlacementKind+  type DocItemPlacement d = 'DocItemInlined++  -- | Defines a function which constructs an unique identifier of given doc item,+  -- if it has been decided to put the doc item into definitions section.+  --+  -- Identifier should be unique both among doc items of the same type and items+  -- of other types. Thus, consider using "typeId-contentId" pattern.+  docItemRef :: d -> DocItemRef (DocItemPlacement d)+  default docItemRef+    :: (DocItemPlacement d ~ 'DocItemInlined)+    => d -> DocItemRef (DocItemPlacement d)+  docItemRef _ = DocItemNoRef++  -- | Render given doc item to Markdown, preferably one line,+  -- optionally with header.+  --+  -- Accepts the smallest allowed level of header.+  -- (Using smaller value than provided one will interfere with existing+  -- headers thus delivering mess).+  docItemToMarkdown :: HeaderLevel -> d -> Markdown++  -- | All doc items which this doc item refers to.+  --+  -- They will automatically be put to definitions as soon as given doc item+  -- is detected.+  docItemDependencies :: d -> [SomeDocDefinitionItem]+  docItemDependencies _ = []++  -- | This function accepts doc items put under the same section in the order+  -- in which they appeared in the contract and returns their new desired order.+  -- It's also fine to use this function for filtering or merging doc items.+  --+  -- Default implementation+  -- * leaves inlined items as is;+  -- * for items put to definitions, lexicographically sorts them by their id.+  docItemsOrder :: [d] -> [d]+  docItemsOrder = \case+    [] -> []+    docItems@(someDocItem : _) -> case docItemRef someDocItem of+      DocItemNoRef -> docItems+      DocItemRef _ -> docItemsOrderById docItems++-- | Get doc item position at term-level.+docItemPosition :: forall d. DocItem d => DocItemPos+docItemPosition = DocItemPos $ natVal (Proxy @(DocItemPosition d))++-- | Render an item into Markdown block with all required adjustments.+docItemToMarkdownFull :: DocItem d => HeaderLevel -> d -> Markdown+docItemToMarkdownFull l d =+  manchor <> docItemToMarkdown l d <> "\n\n"+  where+    manchor = case docItemRef d of+      DocItemRef (DocItemId docItemId) -> mdAnchor docItemId+      DocItemNoRef -> ""++-- | Order items by their 'docItemId'.+docItemsOrderById+  :: forall d. (DocItem d, DocItemPlacement d ~ 'DocItemInDefinitions)+  => [d] -> [d]+docItemsOrderById docItems =+  let getDocItemId :: d -> DocItemId+      getDocItemId d = case docItemRef d of { DocItemRef di -> di }+  in sortOn getDocItemId docItems++-- | Make a reference to doc item in definitions.+docDefinitionRef+  :: (DocItem d, DocItemPlacement d ~ 'DocItemInDefinitions)+  => Markdown -> d -> Markdown+docDefinitionRef refText d = case docItemRef d of+  DocItemRef (DocItemId docItemId) -> mdLocalRef refText docItemId++-- | Some unique identifier of a doc item.+--+-- All doc items which should be refer-able need to have this identifier.+newtype DocItemId = DocItemId Text+  deriving stock (Eq, Ord, Show)++-- | Position of all doc items of some type.+newtype DocItemPos = DocItemPos Natural+  deriving stock (Eq, Ord, Show)+  deriving newtype (Buildable)++-- | Where do we place given doc item.+data DocItemPlacementKind+  = DocItemInlined+    -- ^ Placed in the document content itself.+  | DocItemInDefinitions+    -- ^ Placed in dedicated definitions section; can later be referenced.++-- | Defines an identifier which given doc item can be referenced with.+data DocItemRef (p :: DocItemPlacementKind) where+  DocItemRef :: DocItemId -> DocItemRef 'DocItemInDefinitions+  DocItemNoRef :: DocItemRef 'DocItemInlined++-- | How to render section name.+data DocSectionNameStyle+  = DocSectionNameBig+    -- ^ Suitable for block name.+  | DocSectionNameSmall+    -- ^ Suitable for subsection title within block.++-- | Hides some documentation item.+data SomeDocItem where+  SomeDocItem :: DocItem d => d -> SomeDocItem++-- | Hides some documentation item which is put to "definitions" section.+data SomeDocDefinitionItem where+  SomeDocDefinitionItem+    :: (DocItem d, DocItemPlacement d ~ 'DocItemInDefinitions)+    => d -> SomeDocDefinitionItem++instance Eq SomeDocDefinitionItem where+  SomeDocDefinitionItem d1 == SomeDocDefinitionItem d2 =+    d1 `eqExt` d2+instance Ord SomeDocDefinitionItem where+  SomeDocDefinitionItem d1 `compare` SomeDocDefinitionItem d2 =+    d1 `compareExt` d2++-- | To automatically derive @instance Show Michelson.Typed.Instr@ later.+instance Show SomeDocItem where+  show _ = "<doc item>"++type family DOrd d :: Constraint where+  DOrd d = If (DocItemPlacement d == 'DocItemInDefinitions)+             (Ord d) (() :: Constraint)++-- | A map from positions to document elements.+--+-- Note that each value in this map keeps a list of doc items, all of which+-- have the same type (since each doc item type is forced to have unique position).+type DocBlock = Map DocItemPos (NonEmpty SomeDocItem)++-- | Make sure several 'SomeDocItem's have the same type inside.+unifyDocItemsUnsafe+  :: HasCallStack+  => NonEmpty SomeDocItem+  -> (forall d. DocItem d => NonEmpty d -> r)+  -> r+unifyDocItemsUnsafe (SomeDocItem (firstDocItem :: d) :| docItems) cont =+  let+    dis = docItems <&> \(SomeDocItem di) ->+      cast di ?: error (castErr di)+  in cont $ firstDocItem :| dis+  where+    castErr :: Typeable d' => d' -> Text+    castErr (_ :: d') =+      "Non-homogenious doc block: found two doc items of different types: "+      +|| typeRep (Proxy @d) ||+ " and " +|| typeRep (Proxy @d') ||+ ""++-- | Render a documentation block.+docBlockToMarkdown :: HeaderLevel -> DocBlock -> Markdown+docBlockToMarkdown hl block =+  mconcat $ M.elems block <&> \items@(SomeDocItem (_ :: di) :| _) ->+    let sectionName = docItemSectionName @di+        sectionNameStyle = docItemSectionNameStyle @di+        (sectionNameFull, headerLevelDelta) =+          case sectionName of+            Nothing -> ("", id)+            Just sn ->+              let sn' = build sn+              in case sectionNameStyle of+                  DocSectionNameBig ->+                    (mdHeader hl sn', nextHeaderLevel)+                  DocSectionNameSmall ->+                    ( mdSubsectionTitle sn' <> "\n"+                    , error $ "Using headers is not allowed when section name is set small\n\+                              \Make sure docItemToMarkdown @" <> show (typeRep $ Proxy @di) <>+                              "does not use its 'header level' argument"+                    )+        sectionDesc = docItemSectionDescription @di+        sectionDescFull =+          case sectionDesc of+            Nothing -> ""+            Just sd -> sd <> "\n\n"+        content =+          unifyDocItemsUnsafe items $ \dis ->+            mconcat $ docItemsOrder (toList dis) <&> \di ->+              docItemToMarkdownFull (headerLevelDelta hl) di+    in sectionNameFull <> sectionDescFull <> content++someDocItemToBlock :: SomeDocItem -> DocBlock+someDocItemToBlock sdi@(SomeDocItem (_ :: di)) =+  one (docItemPosition @di, one sdi)++-- | A part of documentation to be grouped. Essentially incapsulates 'DocBlock'.++-- One day we may need to define 'Eq' instance for this thing, and probably+-- we can consider any two entities equal for efficiency.+newtype SubDoc = SubDoc DocBlock++-- | Render documentation for 'SubDoc'.+subDocToMarkdown :: HeaderLevel -> SubDoc -> Markdown+subDocToMarkdown hl (SubDoc d) = docBlockToMarkdown hl d++-- | Keeps documentation gathered for some piece of contract code.+--+-- Used for building documentation of a contract.+data ContractDoc = ContractDoc+  { cdContents :: DocBlock+    -- ^ All inlined doc items.+  , cdDefinitions :: DocBlock+    -- ^ Definitions used in document.+    --+    -- Usually you put some large and repetitive descriptions here.+    -- This differs from the document content in that+    -- it contains sections which are always at top-level,+    -- disregard the nesting.+    --+    -- All doc items which define 'docItemId' method go here, and only they.+  , cdDefinitionsSet :: Set SomeDocDefinitionItem+    -- ^ We remember all already declared entries to avoid cyclic dependencies+    -- in documentation items discovery.+  , cdDefinitionIds :: Set DocItemId+    -- ^ We remember all already used identifiers.+    -- (Documentation naturally should not declare multiple items with+    -- the same identifier because that would make references to the respective+    -- anchors ambiguous).+  }++makeLensesWith postfixLFields ''ContractDoc++-- | Contract documentation assembly primarily relies on this instance.+instance Semigroup ContractDoc where+  cd1 <> cd2 = ContractDoc+    { cdContents =+        M.merge+          M.preserveMissing M.preserveMissing+          (M.zipWithMatched $ \_k l r -> l <> r)+          (cdContents cd1) (cdContents cd2)+    , cdDefinitions =+        M.merge+          M.preserveMissing M.preserveMissing+          (M.zipWithMatched $ \_k (l :| ls) rs ->+             let removeDups = filter $ not . (`isDefinedIn` cdDefinitionIds cd1)+             in l :| ls <> removeDups (toList rs)+          )+          (cdDefinitions cd1) (cdDefinitions cd2)+    , cdDefinitionsSet =+        S.union (cdDefinitionsSet cd1) (cdDefinitionsSet cd2)+    , cdDefinitionIds =+        S.union (cdDefinitionIds cd1) (cdDefinitionIds cd2)+    }+    where+      isDefinedIn :: SomeDocItem -> Set DocItemId -> Bool+      isDefinedIn (SomeDocItem di) defs =+        case docItemRef di of+          DocItemNoRef -> False+          DocItemRef docItemId -> docItemId `S.member` defs++instance Monoid ContractDoc where+  mempty = ContractDoc+    { cdContents = M.empty+    , cdDefinitions = M.empty+    , cdDefinitionsSet = S.empty+    , cdDefinitionIds = S.empty+    }++-- | Render given contract documentation to markdown document.+contractDocToMarkdown :: ContractDoc -> LText+contractDocToMarkdown ContractDoc{..} =+  let+    contents =+      docBlockToMarkdown (HeaderLevel 1) cdContents |+ "\n\n"+    definitions+      | null cdDefinitions = ""+      | otherwise =+        "# Definitions\n\n" +| docBlockToMarkdown (HeaderLevel 2) cdDefinitions+    total = fmt (contents <> definitions)+  in LT.strip total <> "\n"++-- | A function which groups a piece of doc under one doc item.+type DocGrouping = SubDoc -> SomeDocItem++instance Show DocGrouping where+  show _ = "<doc grouping>"++-- | Apply given grouping to documentation being built.+docGroupContent :: DocGrouping -> ContractDoc -> ContractDoc+docGroupContent grouping doc =+  doc+  { cdContents = someDocItemToBlock . grouping $ SubDoc (cdContents doc)+  }++----------------------------------------------------------------------------+-- Basic doc items+----------------------------------------------------------------------------++-- | Give a name to document block.+data DName = DName Text SubDoc++instance DocItem DName where+  type DocItemPosition DName = 1+  docItemSectionName = Nothing+  docItemToMarkdown lvl (DName name doc) =+    mdHeader lvl (build name) <>+    subDocToMarkdown (nextHeaderLevel lvl) doc++-- | Description of something.+data DDescription = DDescription Markdown++instance DocItem DDescription where+  type DocItemPosition DDescription = 10+  docItemSectionName = Nothing+  docItemToMarkdown _ (DDescription txt) = build txt++-- | Specify version if given contract.+data DVersion = DVersion Natural++instance DocItem DVersion where+  type DocItemPosition DVersion = 3+  docItemSectionName = Nothing+  docItemToMarkdown _ (DVersion ver) =+    mdSubsection "Version" (build ver)++-- | Specify version if given contract.+data DGitRevision = DGitRevision+  { dgrRepoSettings :: GitRepoSettings+  , dgrCommitSha :: Text+  , dgrCommitDate :: Text+  }++-- | Repository settings for 'DGitRevision'.+newtype GitRepoSettings = GitRepoSettings+  { grsMkGitRevision :: Text -> Text+    -- ^ By commit sha make up a url to that commit in remote repository.++    -- @martoon: I tried to get remote URL automatically, but failed to+    -- find a way. Even "git-link" in emacs performs complex parsing.+  }++morleyRepoSettings :: GitRepoSettings+morleyRepoSettings = GitRepoSettings $ \commit ->+  "https://gitlab.com/morley-framework/morley/blob/" <> commit++-- | Make 'DGitRevision'.+--+-- >>> :t $mkDGitRevision+-- GitRepoSettings -> DGitRevision+mkDGitRevision :: TH.Q TH.Exp+mkDGitRevision = [e| \dgrRepoSettings ->+  DGitRevision+  { dgrRepoSettings+  , dgrCommitSha = $gitHash+  , dgrCommitDate = $gitCommitDate+  }+  |]++instance DocItem DGitRevision where+  type DocItemPosition DGitRevision = 7+  docItemSectionName = Nothing+  docItemToMarkdown _ DGitRevision{..} =+    mconcat $+    [ mdSubsection "Code revision" $+        let link = grsMkGitRevision dgrRepoSettings dgrCommitSha+        in mconcat+           [ mdRef (build $ T.take 7 dgrCommitSha) (build link)+           , " "+           , mdItalic $ "(" <> build dgrCommitDate <> ")"+           ]+    ]++--  | Comment in the doc (mostly used for licenses)+data DComment = DComment Text++instance DocItem DComment where+  type DocItemPosition DComment = 0+  docItemSectionName = Nothing+  docItemToMarkdown _ (DComment commentText) =+    "<!---\n" +| commentText |+ "\n-->"
− src/Michelson/EqParam.hs
@@ -1,66 +0,0 @@--- | Functions to check whether two values are equal if their types--- have parameters and it's not statically known whether they these--- parameters have the same types.--module Michelson.EqParam-  ( eqParam1-  , eqParam2-  , eqParam3-  ) where--import Data.Typeable ((:~:)(..), eqT)---- | Suppose you have a data type `X` with parameter `a` and you have--- two values: `x1 :: X a1` and `x2 :: X a2`. You can't compare them--- using '==', because they have different types. However, you can--- compare them using 'eqParam1' as long as both parameters are--- 'Typeable'.-eqParam1 ::-     forall a1 a2 t.-     ( Typeable a1-     , Typeable a2-     , Eq (t a1)-     )-  => t a1-  -> t a2-  -> Bool-eqParam1 t1 t2 = isJust @() $ do-  Refl <- eqT @a1 @a2-  guard (t1 == t2)---- | Version of 'eqParam1' for types with 2 parameters.-eqParam2 ::-     forall a1 a2 b1 b2 t.-     ( Typeable a1-     , Typeable a2-     , Typeable b1-     , Typeable b2-     , Eq (t a1 b2)-     )-  => t a1 b1-  -> t a2 b2-  -> Bool-eqParam2 t1 t2 = isJust @() $ do-  Refl <- eqT @a1 @a2-  Refl <- eqT @b1 @b2-  guard (t1 == t2)---- | Version of 'eqParam1' for types with 3 parameters.-eqParam3 ::-     forall a1 a2 b1 b2 c1 c2 t.-     ( Typeable a1-     , Typeable a2-     , Typeable b1-     , Typeable b2-     , Typeable c1-     , Typeable c2-     , Eq (t a1 b1 c1)-     )-  => t a1 b1 c1-  -> t a2 b2 c2-  -> Bool-eqParam3 t1 t2 = isJust @() $ do-  Refl <- eqT @a1 @a2-  Refl <- eqT @b1 @b2-  Refl <- eqT @c1 @c2-  guard (t1 == t2)
+ src/Michelson/FailPattern.hs view
@@ -0,0 +1,118 @@+-- | Typical usages of FAILWITH instruction.++module Michelson.FailPattern+  ( TypicalFailWith+  , typicalFailWithTag+  , isTypicalFailWith+  , modifyTypicalFailWith+  ) where++import Data.Singletons (sing)++import Michelson.Text (MText)+import Michelson.Typed++-- | We need this class to pass it to 'SomeConstrainedValue'.+-- 'ConstantScope' is needed because we push a value and 'Typeable' is+-- needed for 'FAILWITH'.+class (Typeable a, ConstantScope a) => ConstantScope' a+instance (Typeable a, ConstantScope a) => ConstantScope' a++-- | This data type captures typical ways to use `FAILWITH` instruction.+-- Each constructor corresponds to a usage pattern.+data TypicalFailWith+  = FailWithString !MText+  -- ^ Push a constant string and fail with it.+  | FailWithConstantPair !MText !(SomeConstrainedValue ConstantScope')+  -- ^ Push a constant pair where the first item is a string and the+  -- second one is an arbitrary constant. Fail afterwards.+  | FailWithStackValue !MText+  -- ^ Push a constant string and apply the 'PAIR' instruction, then fail.++-- | Extract error tag out of 'TypicalFailWith'.+typicalFailWithTag :: TypicalFailWith -> MText+typicalFailWithTag = \case+  FailWithString str -> str+  FailWithConstantPair str _ -> str+  FailWithStackValue str -> str++-- | Check whether given instruction ends with a typical 'FAILWITH'+-- usage. It does not recursively check instructions that can be+-- passed to other instructions.+isTypicalFailWith :: Instr inp out -> Maybe TypicalFailWith+isTypicalFailWith = isTypicalFailWith' . linearizeLeft+  where+    isTypicalFailWith' :: Instr inp out -> Maybe TypicalFailWith+    isTypicalFailWith' =+      \case+        Seq i1 FAILWITH -> isTypicalPreFailWith i1+        _ -> Nothing++    isTypicalPreFailWith ::+      Instr inp (a ': out) -> Maybe TypicalFailWith+    isTypicalPreFailWith =+      \case+        PUSH v -> isTypicalErrorConstant v+        Seq _ (PUSH v) -> isTypicalErrorConstant v++        Seq (PUSH v) PAIR -> FailWithStackValue <$> isStringValue v+        Seq (Seq _ (PUSH v)) PAIR -> FailWithStackValue <$> isStringValue v++        _ -> Nothing++isTypicalErrorConstant ::+  forall t. ConstantScope t => Value t -> Maybe TypicalFailWith+isTypicalErrorConstant v+  | Just str <- isStringValue v = Just (FailWithString str)+  | VPair (VC (CvString str), secondItem) <- v =+      -- We need to pattern match to deduce `singI` for second item of the pair.+      case sing @t of+        STPair {} -> Just (FailWithConstantPair str (SomeConstrainedValue secondItem))+  | otherwise = Nothing++-- | If given instruction ends with a typical 'FAILWITH' usage, modify+-- the tag used there using given transformation function. It can+-- return any value, not necessarily a string.+modifyTypicalFailWith ::+  (HasCallStack, ConstantScope t, Typeable t) =>+  (MText -> Value t) -> Instr inp out -> Instr inp out+modifyTypicalFailWith f = modifyTypicalFailWith' . linearizeLeft+  where+    modifyTypicalFailWith' :: HasCallStack => Instr inp out -> Instr inp out+    modifyTypicalFailWith' =+      \case+        Seq i1 FAILWITH ->+          case i1 of+            PUSH v -> onPush v+            Seq i0 (PUSH v) -> Seq i0 (onPush v)++            -- It is quite hard to move the body of these very similar+            -- cases into a separate function because involved types+            -- are quite sophisticated.+            Seq (PUSH v) PAIR+              | _ :: Value a <- v+              , _ :: Instr (b ': s) ('TPair a b ': s) <- i1 ->+                case sing @('TPair a b) of+                  STPair {} -> case isStringValue v of+                    Just str -> PUSH (f str) `Seq` PAIR `Seq` FAILWITH+                    Nothing -> PUSH v `Seq` PAIR `Seq` FAILWITH+            Seq (Seq i0 (PUSH v)) PAIR+              | _ :: Value a <- v+              , _ :: Instr s0 ('TPair a b ': s) <- i1 ->+                case sing @('TPair a b) of+                  STPair {} -> Seq i0 $ case isStringValue v of+                    Just str -> PUSH (f str) `Seq` PAIR `Seq` FAILWITH+                    Nothing -> PUSH v `Seq` PAIR `Seq` FAILWITH++            _ -> Seq i1 FAILWITH++        i -> i++    onPush ::+      (HasCallStack, Typeable v, ConstantScope v) => Value v -> Instr inp out+    onPush v = case isTypicalErrorConstant v of+      Just (FailWithString str) -> PUSH (f str) `Seq` FAILWITH+      Just (FailWithConstantPair str (SomeConstrainedValue arg)) ->+        PUSH (VPair (f str, arg)) `Seq` FAILWITH+      Just _ -> error "Unexpected TypicalFailWith"+      Nothing -> PUSH v `Seq` FAILWITH
src/Michelson/Interpret.hs view
@@ -2,6 +2,8 @@  -- | Module, containing function to interpret Michelson -- instructions against given context and input stack.++-- TODO [TM-280]: allow calling specific entrypoint module Michelson.Interpret   ( ContractEnv (..)   , InterpreterState (..)@@ -14,11 +16,14 @@    , interpret   , interpretRepeated+  , interpretInstr   , ContractReturn ++  , interpretSome   , interpretUntyped-  , InterpretUntypedError (..)-  , InterpretUntypedResult (..)+  , InterpretError (..)+  , InterpretResult (..)   , runInstr   , runInstrNoGas   , runUnpack@@ -27,38 +32,35 @@ import Prelude hiding (EQ, GT, LT)  import Control.Monad.Except (throwError)+import Data.Default (Default(..))+import Data.Constraint (Dict (..)) import qualified Data.Map as Map-import Data.Default (Default (..)) import qualified Data.Set as Set import Data.Singletons (SingI(..)) import Data.Typeable ((:~:)(..)) import Data.Vinyl (Rec(..), (<+>))-import Fmt (Buildable(build), Builder, genericF)-import Michelson.EqParam (eqParam1, eqParam2)+import Fmt (Buildable(build), Builder, genericF, pretty)  import Michelson.Interpret.Pack (packValue')-import Michelson.Interpret.Unpack (UnpackError, unpackValue', UnpackEnv (..))+import Michelson.Interpret.Unpack (UnpackError, unpackValue') import Michelson.TypeCheck-  ( SomeContract(..), SomeValue(..), TCError, TcOriginatedContracts,-  TCTypeError(..), compareTypes, eqType, runTypeCheck, typeCheckContract, typeCheckValue)+  (SomeContract(..), SomeNotedValue(..), TCError, TCTypeError(..), TcOriginatedContracts,+  eqType, runTypeCheck, typeCheckContract, typeCheckValue) import Michelson.Typed-  (CValue(..), Contract, CreateAccount(..), CreateContract(..), HasNoBigMap, HasNoOp, Instr(..),-  OpPresence(..), Operation'(..), Operation, SetDelegate(..), Sing(..), T(..), TransferTokens(..), Value'(..),-  extractNotes, fromUType, withSomeSingT) import qualified Michelson.Typed as T-import Michelson.Typed.Arith import Michelson.Typed.Convert (convertContract, untypeValue)-import Michelson.Typed.Polymorphic import qualified Michelson.Untyped as U-import Util.Peano (Peano, LongerThan, Sing(SS, SZ)) import Tezos.Address (Address(..))-import Tezos.Core (Mutez, Timestamp(..))+import Tezos.Core (ChainId, Mutez, Timestamp) import Tezos.Crypto (KeyHash, blake2b, checkSignature, hashKey, sha256, sha512)+import Util.Peano (LongerThan, Peano, Sing(SS, SZ))+import Util.Typeable+import Util.Type  -- | Environment for contract execution. data ContractEnv = ContractEnv   { ceNow :: !Timestamp-  -- ^ Timestamp of the block whose validation triggered this execution.+  -- ^ Timestamp returned by the 'NOW' instruction.   , ceMaxSteps :: !RemainingSteps   -- ^ Number of steps after which execution unconditionally terminates.   , ceBalance :: !Mutez@@ -74,6 +76,8 @@   -- ^ The contract that initiated the current internal transaction.   , ceAmount :: !Mutez   -- ^ Amount of the current transaction.+  , ceChainId :: !ChainId+  -- ^ Identifier of the current chain.   }  -- | Represents `[FAILED]` state of a Michelson program. Contains@@ -83,6 +87,7 @@   MichelsonArithError :: (Typeable n, Typeable m) => ArithError (CValue n) (CValue m) -> MichelsonFailed   MichelsonGasExhaustion :: MichelsonFailed   MichelsonFailedTestAssert :: Text -> MichelsonFailed+  MichelsonAmbigousEpRef :: EpName -> EpAddress -> MichelsonFailed  deriving instance Show MichelsonFailed @@ -95,6 +100,9 @@   MichelsonGasExhaustion == _ = False   MichelsonFailedTestAssert t1 == MichelsonFailedTestAssert t2 = t1 == t2   MichelsonFailedTestAssert _ == _ = False+  MichelsonAmbigousEpRef ep1 epAddr1 == MichelsonAmbigousEpRef ep2 epAddr2 =+    ep1 == ep2 && epAddr1 == epAddr2+  MichelsonAmbigousEpRef _ _ == _ = False  instance Buildable MichelsonFailed where   build =@@ -105,6 +113,9 @@       MichelsonGasExhaustion ->         "Gas limit exceeded on contract execution"       MichelsonFailedTestAssert t -> build t+      MichelsonAmbigousEpRef instrEp epAddr ->+        "Ambigous entrypoint reference. `CONTRACT %" <> build instrEp <> "` \+        \called over address " <> build epAddr     where       formatValue :: forall t . SingI t => Value' Instr t -> Builder       formatValue v =@@ -112,7 +123,7 @@           OpPresent -> "<value with operations>"           OpAbsent -> build (untypeValue v) -data InterpretUntypedError+data InterpretError   = RuntimeFailure (MichelsonFailed, MorleyLogs)   | IllTypedContract TCError   | IllTypedParam TCError@@ -121,25 +132,33 @@   | UnexpectedStorageType TCTypeError   deriving (Generic) -deriving instance Show InterpretUntypedError+deriving instance Show InterpretError -instance Buildable InterpretUntypedError where+instance Buildable InterpretError where   build = genericF -data InterpretUntypedResult where-  InterpretUntypedResult-    :: ( Typeable st-       , SingI st-       , HasNoOp st-       )+data InterpretResult where+  InterpretResult+    :: ( StorageScope st )     => { iurOps :: [Operation]        , iurNewStorage :: T.Value st        , iurNewState   :: InterpreterState        }-    -> InterpretUntypedResult+    -> InterpretResult -deriving instance Show InterpretUntypedResult+deriving instance Show InterpretResult +constructIR ::+  (StorageScope st) =>+  (([Operation], Value' Instr st), InterpreterState) ->+  InterpretResult+constructIR ((ops, val), st) =+  InterpretResult+  { iurOps = ops+  , iurNewStorage = val+  , iurNewState = st+  }+ -- | Morley interpreter state newtype MorleyLogs = MorleyLogs   { unMorleyLogs :: [Text]@@ -150,20 +169,20 @@ noMorleyLogs = MorleyLogs []  -- | Interpret a contract without performing any side effects.+-- This function uses untyped representation of contract, parameter and storage.+-- Mostly used for testing. interpretUntyped   :: U.Contract   -> U.Value   -> U.Value   -> ContractEnv-  -> Either InterpretUntypedError InterpretUntypedResult+  -> Either InterpretError InterpretResult interpretUntyped U.Contract{..} paramU initStU env = do-  (SomeContract (instr :: Contract cp st) _ _)+  SomeContract (FullContract (instr :: Contract cp st) _ _)       <- first IllTypedContract $ typeCheckContract (ceContracts env)             (U.Contract para stor code)-  withSomeSingT (fromUType para) $ \sgp ->-    withSomeSingT (fromUType stor) $ \sgs -> do-      ntp <- first (UnexpectedParamType . ExtractionTypeMismatch) $ extractNotes para sgp-      nts <- first (UnexpectedStorageType . ExtractionTypeMismatch) $ extractNotes stor sgs+  withUType para $ \((sgp :: Sing p), (ntp :: Notes p)) ->+    withUType stor $ \((sgs :: Sing s), (nts :: Notes s)) -> do       paramV :::: ((_ :: Sing cp1), _)           <- first IllTypedParam $ runTypeCheck para (ceContracts env) $ usingReaderT def $                typeCheckValue paramU (sgp, ntp)@@ -172,21 +191,34 @@                typeCheckValue initStU (sgs, nts)       Refl <- first UnexpectedStorageType $ eqType @st @st1       Refl <- first UnexpectedParamType   $ eqType @cp @cp1-      bimap RuntimeFailure constructIUR $+      bimap RuntimeFailure constructIR $         toRes $ interpret instr paramV initStV env   where     toRes (ei, s) = bimap (,isMorleyLogs s) (,s) ei -    constructIUR ::-      (Typeable st, SingI st, HasNoOp st) =>-      (([Operation], Value' Instr st), InterpreterState) ->-      InterpretUntypedResult-    constructIUR ((ops, val), st) =-      InterpretUntypedResult-      { iurOps = ops-      , iurNewStorage = val-      , iurNewState = st-      }+-- | Interpret a contract without performing any side effects using typed+-- representation of contract, parameter and storage.+interpretSome+  :: SomeContract+  -> SomeValue+  -> SomeValue+  -> ContractEnv+  -> Either InterpretError InterpretResult+interpretSome+  (SomeContract (FullContract (code :: Contract cp st) _ _))+  (SomeValue (param :: T.Value cp1))+  (SomeValue (store :: T.Value st1))+  env = do+  Refl <- first UnexpectedStorageType $ eqType @st @st1+  Refl <- first UnexpectedParamType $ eqType @cp @cp1+  -- If one of these error happened, then probably there is a bug+  -- in implementation. These checks are required because we pass+  -- code, parameter and storage in representation, that hides their+  -- actual type, it is done to simplify runtime engine implementation.+  bimap RuntimeFailure constructIR $+    toRes $ interpret code param store env+  where+    toRes (ei, s) = bimap (,isMorleyLogs s) (,s) ei  type ContractReturn st =   (Either MichelsonFailed ([Operation], T.Value st), InterpreterState)@@ -239,6 +271,22 @@         Left err ->           (Left err, ist) +-- | Interpret an instruction in vacuum, putting no extra contraints on+-- its execution.+--+-- Mostly for testing purposes.+interpretInstr+  :: ContractEnv+  -> Instr inp out+  -> Rec T.Value inp+  -> Either MichelsonFailed (Rec T.Value out)+interpretInstr env instr inpSt =+  fst $+  runEvalOp+    (runInstr instr inpSt)+    env+    InterpreterState{ isMorleyLogs = MorleyLogs [], isRemainingSteps = 9999999999 }+ data SomeItStack where   SomeItStack :: T.ExtInstr inp -> Rec T.Value inp -> SomeItStack @@ -270,6 +318,7 @@   -> Rec (T.Value) inp   -> EvalOp (Rec (T.Value) out) runInstr i@(Seq _i1 _i2) r = runInstrImpl runInstr i r+runInstr i@(InstrWithNotes _ _i1) r = runInstrImpl runInstr i r runInstr i@Nop r = runInstrImpl runInstr i r runInstr i@(Nested _) r = runInstrImpl runInstr i r runInstr i r = do@@ -284,6 +333,7 @@   :: forall a b . T.Instr a b -> Rec T.Value a -> EvalOp (Rec T.Value b) runInstrNoGas = runInstrImpl runInstrNoGas + -- | Function to interpret Michelson instruction(s) against given stack. runInstrImpl     :: (forall inp1 out1 .@@ -297,12 +347,47 @@         -> EvalOp (Rec T.Value out)       ) runInstrImpl runner (Seq i1 i2) r = runner i1 r >>= \r' -> runner i2 r'+runInstrImpl runner (InstrWithNotes _ i) r = runner i r+runInstrImpl runner (FrameInstr (_ :: Proxy s) i) r = do+  let (inp, end) = rsplit @_ @_ @s r+  out <- runInstrImpl runner i inp+  return (out <+> end) runInstrImpl _ Nop r = pure $ r runInstrImpl _ (Ext nop) r = r <$ interpretExt (SomeItStack nop r) runInstrImpl runner (Nested sq) r = runInstrImpl runner sq r+runInstrImpl runner (DocGroup _ sq) r = runInstrImpl runner sq r runInstrImpl _ DROP (_ :& r) = pure $ r+runInstrImpl runner (DROPN s) stack =+  case s of+    SZ -> pure stack+    SS s' -> case stack of+      -- Note: we intentionally do not use `runner` to recursively+      -- interpret `DROPN` here.+      -- All these recursive calls together correspond to a single+      -- Michelson instruction call.+      -- This recursion is implementation detail of `DROPN`.+      -- The same reasoning applies to other instructions parameterized+      -- by a natural number like 'DIPN'.+      (_ :& r) -> runInstrImpl runner (DROPN s') r runInstrImpl _ DUP (a :& r) = pure $ a :& a :& r runInstrImpl _ SWAP (a :& b :& r) = pure $ b :& a :& r+runInstrImpl _ (DIG nSing0) input0 =+  pure $ go (nSing0, input0)+  where+    go :: forall (n :: Peano) inp out a. T.ConstraintDIG n inp out a =>+      (Sing n, Rec T.Value inp) -> Rec T.Value out+    go = \case+      (SZ, stack) ->  stack+      (SS nSing, b :& r) -> case go (nSing, r) of+        (a :& resTail) -> a :& b :& resTail+runInstrImpl _ (DUG nSing0) input0 =+  pure $ go (nSing0, input0)+  where+    go :: forall (n :: Peano) inp out a. T.ConstraintDUG n inp out a =>+      (Sing n, Rec T.Value inp) -> Rec T.Value out+    go = \case+      (SZ, stack) -> stack+      (SS s', a :& b :& r) -> b :& go (s', a :& r) runInstrImpl _ (PUSH v) r = pure $ v :& r runInstrImpl _ SOME (a :& r) = pure $ VOption (Just a) :& r runInstrImpl _ NONE r = pure $ VOption Nothing :& r@@ -310,8 +395,8 @@ runInstrImpl runner (IF_NONE _bNone bJust) (VOption (Just a) :& r) = runner bJust (a :& r) runInstrImpl runner (IF_NONE bNone _bJust) (VOption Nothing :& r) = runner bNone r runInstrImpl _ PAIR (a :& b :& r) = pure $ VPair (a, b) :& r-runInstrImpl _ CAR (VPair (a, _b) :& r) = pure $ a :& r-runInstrImpl _ CDR (VPair (_a, b) :& r) = pure $ b :& r+runInstrImpl _ (AnnCAR _) (VPair (a, _b) :& r) = pure $ a :& r+runInstrImpl _ (AnnCDR _) (VPair (_a, b) :& r) = pure $ b :& r runInstrImpl _ LEFT (a :& r) = pure $ (VOr $ Left a) :& r runInstrImpl _ RIGHT (b :& r) = pure $ (VOr $ Right b) :& r runInstrImpl runner (IF_LEFT bLeft _) (VOr (Left a) :& r) = runner bLeft (a :& r)@@ -324,6 +409,7 @@ runInstrImpl _ SIZE (a :& r) = pure $ VC (CvNat $ (fromInteger . toInteger) $ evalSize a) :& r runInstrImpl _ EMPTY_SET r = pure $ VSet Set.empty :& r runInstrImpl _ EMPTY_MAP r = pure $ VMap Map.empty :& r+runInstrImpl _ EMPTY_BIG_MAP r = pure $ VBigMap Map.empty :& r runInstrImpl runner (MAP ops) (a :& r) =   case ops of     (code :: Instr (MapOpInp c ': s) (b ': s)) -> do@@ -355,19 +441,28 @@   res <- runner ops (a :& r)   runner  (LOOP_LEFT ops) res runInstrImpl _ (LAMBDA lam) r = pure $ lam :& r-runInstrImpl runner EXEC (a :& VLam lBody :& r) = do+runInstrImpl runner EXEC (a :& VLam (T.rfAnyInstr -> lBody) :& r) = do   res <- runner lBody (a :& RNil)   pure $ res <+> r+runInstrImpl _ APPLY ((a :: T.Value a) :& VLam lBody :& r) = do+  pure $ VLam (T.rfMapAnyInstr doApply lBody) :& r+  where+    doApply :: Instr ('TPair a i ': s) o -> Instr (i ': s) o+    doApply b = PUSH a `Seq` PAIR `Seq` Nested b runInstrImpl runner (DIP i) (a :& r) = do   res <- runner i r   pure $ a :& res+runInstrImpl runner (DIPN s i) stack =+  case s of+    SZ -> runner i stack+    SS s' -> case stack of+      (a :& r) -> (a :&) <$> runInstrImpl runner (DIPN s' i) r runInstrImpl _ FAILWITH (a :& _) = throwError $ MichelsonFailedWith a runInstrImpl _ CAST (a :& r) = pure $ a :& r runInstrImpl _ RENAME (a :& r) = pure $ a :& r runInstrImpl _ PACK (a :& r) = pure $ (VC $ CvBytes $ packValue' a) :& r-runInstrImpl _ UNPACK (VC (CvBytes a) :& r) = do-  env <- asks ceContracts-  pure $ (VOption . rightToMaybe $ runUnpack env a) :& r+runInstrImpl _ UNPACK (VC (CvBytes a) :& r) =+  pure $ (VOption . rightToMaybe $ runUnpack a) :& r runInstrImpl _ CONCAT (a :& b :& r) = pure $ evalConcat a b :& r runInstrImpl _ CONCAT' (VList a :& r) = pure $ evalConcat' a :& r runInstrImpl _ SLICE (VC (CvNat o) :& VC (CvNat l) :& s :& r) =@@ -397,39 +492,69 @@ runInstrImpl _ LE (VC a :& rest) = pure $ VC (evalUnaryArithOp (Proxy @Le) a) :& rest runInstrImpl _ GE (VC a :& rest) = pure $ VC (evalUnaryArithOp (Proxy @Ge) a) :& rest runInstrImpl _ INT (VC (CvNat n) :& r) = pure $ VC (CvInt $ toInteger n) :& r-runInstrImpl _ SELF r = do+runInstrImpl _ (SELF :: Instr inp out) r = do   ContractEnv{..} <- ask-  pure $ VContract ceSelf :& r-runInstrImpl _ (CONTRACT (nt :: T.Notes p)) (VC (CvAddress addr) :& r) = do+  case Proxy @out of+    (_ :: Proxy ('TContract cp ': s)) -> do+      Dict <- pure $+        T.opAbsense (sing @cp)+        ?: error "Unexpected Operation in contract type returned by SELF"+      Dict <- pure $+        T.bigMapAbsense (sing @cp)+        ?: error "Unexpected BigMap in contract type returned by SELF"+      pure $ VContract ceSelf def :& r+runInstrImpl _ (CONTRACT (nt :: T.Notes a) instrEpName) (VC (CvAddress epAddr) :& r) = do   ContractEnv{..} <- ask-  case Map.lookup addr ceContracts of-    Just tc -> do-      pure $-        either (const $ VOption Nothing)-               (const $ VOption (Just $ VContract addr))-               (compareTypes (sing @p, nt) tc)-        :& r-    Nothing -> pure $ VOption Nothing :& r+  let T.EpAddress addr addrEpName = epAddr+  epName <- case (instrEpName, addrEpName) of+    (NoEpName, NoEpName) -> pure NoEpName+    (NoEpName, en) -> pure en+    (en, NoEpName) -> pure en+    _ -> throwError $ MichelsonAmbigousEpRef instrEpName epAddr++  pure $ case addr of+    KeyAddress _ ->+      castContract addr epName T.tyImplicitAccountParam :& r+    ContractAddress ca ->+      case Map.lookup ca ceContracts of+        Just tc -> withUType tc $ \tc'@(tcSing, _) ->+          case (T.checkOpPresence tcSing, T.checkNestedBigMapsPresence tcSing) of+            (OpAbsent, NestedBigMapsAbsent) -> castContract addr epName tc' :& r+            _ -> error $ "Illegal type in parameter of env contract: " <> pretty tc+            -- TODO: we can do this safely once 'TcOriginatedContracts' stores+            -- typed stuff.+        Nothing -> VOption Nothing :& r+  where+  castContract+    :: forall p. T.ParameterScope p+    => Address -> EpName -> (Sing p, T.Notes p) -> T.Value ('TOption ('TContract a))+  castContract addr epName param =+    fromMaybe (VOption Nothing) $+    T.mkEntryPointCall epName param $ \((a' :: T.Notes a'), epc) ->+      case eqType @a @a' of+        Left _ -> VOption Nothing+        Right Refl -> case T.converge nt a' of+          Left _ -> VOption Nothing+          Right _ -> VOption (Just $ VContract addr (T.SomeEpc epc))+ runInstrImpl _ TRANSFER_TOKENS (p :& VC (CvMutez mutez) :& contract :& r) =   pure $ VOp (OpTransferTokens $ TransferTokens p mutez contract) :& r runInstrImpl _ SET_DELEGATE (VOption mbKeyHash :& r) =   case mbKeyHash of     Just (VC (CvKeyHash k)) -> pure $ VOp (OpSetDelegate $ SetDelegate $ Just k) :& r     Nothing -> pure $ VOp (OpSetDelegate $ SetDelegate $ Nothing) :& r-runInstrImpl _ CREATE_ACCOUNT-  (VC (CvKeyHash k) :& VOption mbKeyHash :&-    (VC (CvBool spendable)) :& (VC (CvMutez m)) :& r) =-  pure (VOp (OpCreateAccount $ CreateAccount k (unwrapMbKeyHash mbKeyHash) spendable m)-    :& (VC . CvAddress) (KeyAddress k) :& r)-runInstrImpl _ (CREATE_CONTRACT ops)-  (VC (CvKeyHash k) :& VOption mbKeyHash :& (VC (CvBool spendable)) :&-    (VC (CvBool delegetable)) :& (VC (CvMutez m)) :& g :& r) =-  pure (VOp (OpCreateContract $-    CreateContract k (unwrapMbKeyHash mbKeyHash) spendable delegetable m g ops)-    :& (VC . CvAddress) (U.mkContractAddress $-      createOrigOp k mbKeyHash spendable delegetable m ops g) :& r)+runInstrImpl _ (CREATE_CONTRACT fullContract)+  (VOption mbKeyHash :& (VC (CvMutez m)) :& g :& r) = do+  originator <- ceSelf <$> ask+  let ops = fcCode fullContract+  let resAddr = U.mkContractAddress $ createOrigOp originator mbKeyHash m ops g+  let resEpAddr = EpAddress resAddr def+  let resOp = CreateContract originator (unwrapMbKeyHash mbKeyHash) m g ops+  pure $ VOp (OpCreateContract resOp)+      :& (VC (CvAddress resEpAddr))+      :& r runInstrImpl _ IMPLICIT_ACCOUNT (VC (CvKeyHash k) :& r) =-  pure $ VContract (KeyAddress k) :& r+  pure $ VContract (KeyAddress k) def :& r runInstrImpl _ NOW r = do   ContractEnv{..} <- ask   pure $ VC (CvTimestamp ceNow) :& r@@ -450,11 +575,15 @@   pure $ VC (CvNat $ (fromInteger . toInteger) x) :& r runInstrImpl _ SOURCE r = do   ContractEnv{..} <- ask-  pure $ VC (CvAddress ceSource) :& r+  pure $ VC (CvAddress $ EpAddress ceSource def) :& r runInstrImpl _ SENDER r = do   ContractEnv{..} <- ask-  pure $ VC (CvAddress ceSender) :& r-runInstrImpl _ ADDRESS (VContract a :& r) = pure $ VC (CvAddress a) :& r+  pure $ VC (CvAddress $ EpAddress ceSender def) :& r+runInstrImpl _ ADDRESS (VContract a sepc :& r) =+  pure $ VC (CvAddress $ EpAddress a (sepcName sepc)) :& r+runInstrImpl _ CHAIN_ID r = do+  ContractEnv{..} <- ask+  pure $ VChainId ceChainId :& r  -- | Evaluates an arithmetic operation and either fails or proceeds. runArithOp@@ -469,31 +598,28 @@  -- | Unpacks given raw data into a typed value. runUnpack-  :: forall t. (SingI t, HasNoOp t, HasNoBigMap t)-  => TcOriginatedContracts-  -> ByteString+  :: forall t. (UnpackedValScope t)+  => ByteString   -> Either UnpackError (T.Value t)-runUnpack contracts bs =+runUnpack bs =   -- TODO [TM-80] Gas consumption here should depend on unpacked data size   -- and size of resulting expression, errors would also spend some (all equally).   -- Fortunatelly, the inner decoding logic does not need to know anything about gas use.-  unpackValue' (UnpackEnv contracts) bs+  unpackValue' bs  createOrigOp-  :: (SingI param, SingI store, HasNoOp store)-  => KeyHash+  :: (SingI param, StorageScope store)+  => Address   -> Maybe (T.Value ('Tc 'U.CKeyHash))-  -> Bool -> Bool -> Mutez+  -> Mutez   -> Contract param store   -> Value' Instr store   -> U.OriginationOperation-createOrigOp k mbKeyHash delegetable spendable m contract g =+createOrigOp originator mbDelegate bal contract g =   U.OriginationOperation-    { ooManager = k-    , ooDelegate = (unwrapMbKeyHash mbKeyHash)-    , ooSpendable = spendable-    , ooDelegatable = delegetable-    , ooBalance = m+    { ooOriginator = originator+    , ooDelegate = unwrapMbKeyHash mbDelegate+    , ooBalance = bal     , ooStorage = untypeValue g     , ooContract = convertContract contract     }@@ -514,6 +640,8 @@   unless succeeded $ do     interpretExt (SomeItStack (T.PRINT pc) st)     throwError $ MichelsonFailedTestAssert $ "TEST_ASSERT " <> nm <> " failed"++interpretExt (SomeItStack T.DOC_ITEM{} _) = pass  -- | Access given stack reference (in CPS style). withStackElem
src/Michelson/Interpret/Pack.hs view
@@ -2,8 +2,13 @@ -- -- This is nearly symmetric to adjacent Unpack.hs module. module Michelson.Interpret.Pack-  ( packValue+  ( packCode'+  , packT'+  , packValue   , packValue'++    -- * Internals+  , encodeIntPayload   ) where  import Prelude hiding (EQ, GT, LT)@@ -18,33 +23,48 @@  import Michelson.Text import Michelson.Typed-import Tezos.Address (Address(..))-import Tezos.Core (Mutez(..), timestampToSeconds)-import Tezos.Crypto (KeyHash(..), PublicKey(unPublicKey), Signature(..))+import Tezos.Address (Address(..), ContractHash(..))+import Tezos.Core (ChainId(..), Mutez(..), timestampToSeconds)+import Tezos.Crypto (KeyHash(..), KeyHashTag(..), PublicKey(..), signatureToBytes)+import qualified Tezos.Crypto.Ed25519 as Ed25519+import qualified Tezos.Crypto.P256 as P256+import qualified Tezos.Crypto.Secp256k1 as Secp256k1+import Util.Peano (peanoValSing)  -- | Serialize a value given to @PACK@ instruction.-packValue :: (SingI t, HasNoOp t, HasNoBigMap t) => Value t -> LByteString+packValue :: PackedValScope t => Value t -> LByteString packValue x = "\x05" <> encodeValue x  -- | Same as 'packValue', for strict bytestring.-packValue' :: (SingI t, HasNoOp t, HasNoBigMap t) => Value t -> ByteString+packValue' :: PackedValScope t => Value t -> ByteString packValue' = LBS.toStrict . packValue -encodeValue :: forall t. (SingI t, HasNoOp t, HasNoBigMap t) => Value t -> LByteString+packT' :: forall (t :: T). SingI t => ByteString+packT' = LBS.toStrict $ encodeT' @t++packCode' :: Instr inp out -> ByteString+packCode' = LBS.toStrict . encodeInstrs++surround :: LByteString -> LByteString -> ByteString -> LByteString+surround prefix suffix main = prefix <> LBS.fromStrict main <> suffix++encodeValue :: forall t. PackedValScope t => Value t -> LByteString encodeValue val = case (val, sing @t) of   (VC cval, _) -> encodeCValue cval-  (VKey s, _) ->-    encodeBytes "\x00" "" $-      LBS.fromStrict . ByteArray.convert $ unPublicKey s+  (VKey s, _) -> encodeBytes . LBS.fromStrict $ case s of+    PublicKeyEd25519 pk -> "\x00" <> Ed25519.publicKeyToBytes pk+    PublicKeySecp256k1 pk -> "\x01" <> Secp256k1.publicKeyToBytes pk+    PublicKeyP256 pk -> "\x02" <> P256.publicKeyToBytes pk   (VUnit, _) -> "\x03\x0b"-  (VSignature x, _) ->-    encodeBytes "" "" $-      LBS.fromStrict . ByteArray.convert $ unSignature x+  (VSignature x, _) -> encodeBytes . LBS.fromStrict $ signatureToBytes x+  (VChainId x, _) ->+    encodeBytes . LBS.fromStrict $+      ByteArray.convert (unChainId x)   (VOption (Just x), STOption _) -> "\x05\x09" <> encodeValue x   (VOption Nothing, _) -> "\x03\x06"   (VList xs, STList _) -> encodeList encodeValue xs   (VSet xs, _) -> encodeList encodeCValue (toList xs)-  (VContract addr, _) -> encodeAddress addr+  (VContract addr sepc, _) -> encodeEpAddress $ EpAddress addr (sepcName sepc)   (VPair (v1, v2), STPair l _) ->     case (checkOpPresence l, checkBigMapPresence l) of       (OpAbsent, BigMapAbsent) -> "\x07\x07" <> encodeValue v1 <> encodeValue v2@@ -54,7 +74,7 @@   (VOr (Right v), STOr l _) ->     case (checkOpPresence l, checkBigMapPresence l) of       (OpAbsent, BigMapAbsent) -> "\x05\x08" <> encodeValue v-  (VLam lam, _) -> encodeInstrs lam+  (VLam lam, _) -> encodeInstrs $ rfAnyInstr lam   (VMap m, STMap _ _) -> encodeMap m  encodeCValue :: CValue t -> LByteString@@ -62,13 +82,13 @@   CvInt x        -> encodeNumeric x   CvNat x        -> encodeNumeric x   CvString text  -> encodeString text-  CvBytes bytes  -> encodeBytes "" "" (LBS.fromStrict bytes)+  CvBytes bytes  -> encodeBytes (LBS.fromStrict bytes)   CvMutez x      -> encodeNumeric (unMutez x)   CvBool True    -> "\x03\x0a"   CvBool False   -> "\x03\x03"-  CvKeyHash s    -> encodeBytes "\x00" "" (LBS.fromStrict $ unKeyHash s)+  CvKeyHash kh   -> encodeBytes $ encodeKeyHashRaw kh   CvTimestamp x  -> encodeNumeric (timestampToSeconds @Integer x)-  CvAddress addr -> encodeAddress addr+  CvAddress addr -> encodeEpAddress addr  encodeLength :: Int -> LByteString encodeLength = Bi.runPut . Bi.putWord32be . fromIntegral@@ -86,20 +106,35 @@ encodeString text = "\x01" <> encodeAsList (encodeUtf8 $ unMText text)  -- | Encode some raw data.-encodeBytes :: ByteString -> ByteString -> LByteString -> LByteString-encodeBytes (LBS.fromStrict -> prefix) (LBS.fromStrict -> suffix) bs =-  "\x0a" <> encodeAsList (prefix <> bs <> suffix)+encodeBytes :: LByteString -> LByteString+encodeBytes bs =+  "\x0a" <> encodeAsList bs +-- TODO [TM-293]: Probably encode via converting to annotation first+encodeEpName :: EpName -> LByteString+encodeEpName = encodeUtf8 . unEpName+ -- | Encode some map.-encodeMap :: (SingI v, HasNoOp v, HasNoBigMap v) => Map (CValue k) (Value v) -> LByteString+encodeMap :: (PackedValScope v) => Map (CValue k) (Value v) -> LByteString encodeMap m =   encodeList (\(k, v) -> "\x07\x04" <> encodeCValue k <> encodeValue v) (Map.toList m) +encodeKeyHashRaw :: KeyHash -> LByteString+encodeKeyHashRaw kh = (<> LBS.fromStrict (khBytes kh)) $+  case khTag kh of+    KeyHashEd25519 -> "\x00"+    KeyHashSecp256k1 -> "\x01"+    KeyHashP256 -> "\x02"+ encodeAddress :: Address -> LByteString encodeAddress = \case-  KeyAddress keyHash -> encodeBytes "\x00\x00" "" (LBS.fromStrict $ unKeyHash keyHash)-  ContractAddress address -> encodeBytes "\x01" "\x00" (LBS.fromStrict address)+  KeyAddress keyHash -> "\x00" <> (encodeKeyHashRaw keyHash)+  ContractAddress (ContractHash address) -> surround "\x01" "\x00" address +encodeEpAddress :: EpAddress -> LByteString+encodeEpAddress (EpAddress addr epName) =+  encodeBytes $ encodeAddress addr <> encodeEpName epName+ -- | Encode contents of a given number. encodeIntPayload :: Integer -> LByteString encodeIntPayload = LBS.pack . toList . doEncode True@@ -139,20 +174,31 @@ -- | Encode an instruction. encodeInstr :: forall inp out. Instr inp out -> LByteString encodeInstr = \case+  InstrWithNotes _ a -> encodeInstr a+  FrameInstr _ i ->+    encodeInstr i   Seq a b ->     encodeInstr a <> encodeInstr b   Nop ->     mempty   Nested i ->     encodeInstrs i+  DocGroup _ i ->+    encodeInstrs i   Ext _ ->     ""   DROP ->     "\x03\x20"+  DROPN s ->+    "\x05\x20" <> encodeNumeric (peanoValSing s)   DUP ->     "\x03\x21"   SWAP ->     "\x03\x4c"+  DIG s ->+    "\x05\x70" <> encodeNumeric (peanoValSing s)+  DUG s ->+    "\x05\x71" <> encodeNumeric (peanoValSing s)   PUSH (a :: Value t) ->     "\x07\x43" <> encodeT' @t <> encodeValue a   SOME ->@@ -165,9 +211,9 @@     "\x07\x2f" <> encodeInstrs a <> encodeInstrs b   PAIR ->     "\x03\x42"-  CAR ->+  (AnnCAR _) ->     "\x03\x16"-  CDR ->+  (AnnCDR _) ->     "\x03\x17"   LEFT | _ :: Proxy ('TOr l r ': s) <- Proxy @out ->     "\x05\x33" <> encodeT' @r@@ -187,6 +233,8 @@     "\x05\x24" <> encodeT' @('Tc t)   EMPTY_MAP | _ :: Proxy ('TMap k v ': s) <- Proxy @out ->     "\x07\x23" <> encodeT' @('Tc k) <> encodeT' @v+  EMPTY_BIG_MAP | _ :: Proxy ('TBigMap k v ': s) <- Proxy @out ->+    "\x07\x72" <> encodeT' @('Tc k) <> encodeT' @v   MAP a ->     "\x05\x38" <> encodeInstrs a   ITER a ->@@ -209,8 +257,12 @@     encodeLength 0  -- @martoon: dunno where does it come from   EXEC ->     "\x03\x26"+  APPLY ->+    "\x03\x73"   DIP a ->     "\x05\x1f" <> encodeInstrs a+  DIPN s a ->+    "\x07\x1f" <> encodeNumeric (peanoValSing s) <> encodeInstrs a   FAILWITH ->     "\x03\x27"   CAST | _ :: Proxy (t ': s) <- Proxy @out ->@@ -271,15 +323,15 @@     "\x03\x30"   SELF ->     error "SELF should not appear in lambda"-  CONTRACT _ | _ :: Proxy ('TOption ('TContract t) ': s) <- Proxy @out ->+  -- TODO [TM-336]: encode annotation here+  CONTRACT _ _ | _ :: Proxy ('TOption ('TContract t) ': s) <- Proxy @out ->     "\x05\x55" <> encodeT' @t   TRANSFER_TOKENS ->     "\x03\x4d"   SET_DELEGATE ->     "\x03\x4e"-  CREATE_ACCOUNT ->-    "\x03\x1c"-  CREATE_CONTRACT (instr :: Instr '[ 'TPair p g ] '[ 'TPair ('TList 'TOperation) g ]) ->+  CREATE_CONTRACT (FullContract instr _ _)+    | _ :: Instr '[ 'TPair p g ] '[ 'TPair ('TList 'TOperation) g ] <- instr ->     let contents =           [ "\x05\x00" <> encodeT' @p           , "\x05\x01" <> encodeT' @g@@ -314,6 +366,8 @@    "\x03\x48"   ADDRESS ->    "\x03\x54"+  CHAIN_ID ->+   "\x03\x75"  encodeT :: T -> LByteString encodeT = \case@@ -321,6 +375,7 @@   TKey  -> "\x03\x5c"   TUnit -> "\x03\x6c"   TSignature -> "\x03\x67"+  TChainId -> "\x03\x74"   TOption t -> "\x05\x63" <> encodeT t   TList t -> "\x05\x5f" <> encodeT t   TSet t -> "\x05\x66" <> encodeCT t
src/Michelson/Interpret/Unpack.hs view
@@ -15,7 +15,6 @@   ( UnpackError (..)   , unpackValue   , unpackValue'-  , UnpackEnv (..)   ) where  import Prelude hiding (EQ, Ordering(..), get)@@ -29,28 +28,34 @@ import Data.Constraint (Dict(..)) import Data.Default (def) import qualified Data.Kind as Kind+import qualified Data.List as List import qualified Data.Map as Map import qualified Data.Set as Set import Data.Singletons (SingI(..)) import Data.Typeable ((:~:)(..))-import Fmt (Buildable, build, fmt, hexF, (+|), (+||), (|+), (||+))+import Fmt (Buildable, build, fmt, hexF, pretty, (+|), (+||), (|+), (||+)) import Text.Hex (encodeHex)  import Michelson.Text import Michelson.TypeCheck-  (HST(..), SomeHST(..), SomeInstr(..), SomeInstrOut(..), TCError(..), TcOriginatedContracts,-  TypeCheckEnv(..))+  (HST(..), SomeHST(..), SomeInstr(..), SomeInstrOut(..), TCError(..), TypeCheckEnv(..)) import Michelson.TypeCheck.Helpers (ensureDistinctAsc, eqHST1) import Michelson.TypeCheck.Instr (typeCheckList)-import Michelson.Typed (Sing(..))+import Michelson.Typed (RemFail(..), Sing(..), starNotes) import qualified Michelson.Typed as T+import Michelson.Typed.EntryPoints import Michelson.Typed.Scope-  (BigMapPresence(..), HasNoBigMap, HasNoOp, OpPresence(..), bigMapAbsense, checkBigMapPresence,-  checkOpPresence, opAbsense)+  (BigMapPresence(..), ContractPresence(..), OpPresence(..), UnpackedValScope, bigMapAbsense,+  checkBigMapPresence, checkContractTypePresence, checkOpPresence, contractTypeAbsense, opAbsense) import Michelson.Untyped-import Tezos.Address (Address(..))-import Tezos.Core (mkMutez, timestampFromSeconds)-import Tezos.Crypto (KeyHash(..), mkPublicKey, mkSignature)+import Tezos.Address (Address(..), ContractHash(..), parseAddress)+import Tezos.Core+import Tezos.Crypto+  (KeyHash(..), KeyHashTag(..), PublicKey(..), keyHashLengthBytes, mkSignature, parseKeyHash,+  parsePublicKey, parseSignature, signatureLengthBytes)+import qualified Tezos.Crypto.Ed25519 as Ed25519+import qualified Tezos.Crypto.P256 as P256+import qualified Tezos.Crypto.Secp256k1 as Secp256k1  ---------------------------------------------------------------------------- -- Helpers@@ -63,9 +68,8 @@ instance Buildable UnpackError where   build (UnpackError msg) = build msg -data UnpackEnv = UnpackEnv-  { ueContracts :: TcOriginatedContracts-  }+instance Exception UnpackError where+  displayException = pretty  -- | Alias for label attaching. (?) :: Get a -> String -> Get a@@ -87,7 +91,7 @@                    ", but got 0x" +| hexF t' |+ ")"  -- | Fail with "unknown tag" error.-unknownTag :: Text -> Word8 -> Get a+unknownTag :: String -> Word8 -> Get a unknownTag desc tag =   fail . fmt $ "Unknown " <> build desc <> " tag: 0x" <> hexF tag @@ -134,6 +138,46 @@     then return []     else (:) <$> decode <*> manyForced decode +-- | Describes how 'decodeWithTag' should decode tag-dependent data.+-- We expect bytes of such structure: 'tdTag' followed by a bytestring+-- of length 'tdLength'. This bytestring will be passed to 'tdConstructor'.+data TaggedDecoder a where+  TaggedDecoder :: Buildable err =>+    { tdTag :: !Word8+    , tdLength :: !Int+    , tdConstructor :: !(ByteString -> Either err a)+    } -> TaggedDecoder a++-- Common decoder for the case when packed data starts with a tag (1+-- byte) that specifies how to decode remaining data.+-- Usually in this case data is packed as bytes,+-- so the 'Int' argument passed here is the length of that bytestring.+-- See 'decodeAsBytes'.+-- Note that it differs from 'tdLength' because 'Int' argument+-- includes tag byte while 'tdLength' does not.+decodeWithTag :: String -> [TaggedDecoder a] -> Int -> Get a+decodeWithTag what decoders len =+  decodeWithTagSimple what . map (\td -> (tdTag td, tdToGet td)) $ decoders+  where+    tdToGet :: TaggedDecoder a -> Get a+    tdToGet TaggedDecoder {..}+      -- 1 byte here is used for tag.+      | tdLength + 1 /= len =+        fail $ "Wrong length of " +| what |+ ": " +| len |+ ""+      | otherwise = do+          bs <- getByteStringCopy tdLength+          case tdConstructor bs of+            Left err -> fail $ "Wrong " +| what |+ ": " +| err |+ ""+            Right res -> pure res++decodeWithTagSimple :: String -> [(Word8, Get a)] -> Get a+decodeWithTagSimple what decoders = Get.label what $ do+  tag <- Get.label (what <> " tag") Get.getWord8+  -- Number of decoders is usually small, so linear runtime lookup should be ok.+  case List.find ((tag ==) . fst) decoders of+    Nothing -> unknownTag what tag+    Just (_, decoder) -> decoder+ ---------------------------------------------------------------------------- -- Michelson serialisation ----------------------------------------------------------------------------@@ -161,89 +205,101 @@ -- | Deserialize bytes into the given value. -- Suitable for @UNPACK@ operation only. unpackValue-  :: (SingI t, HasNoOp t, HasNoBigMap t)-  => UnpackEnv -> LByteString -> Either UnpackError (T.Value t)-unpackValue env bs =-  case Get.runGetOrFail (unpackDecoder env) bs of+  :: (UnpackedValScope t)+  => LByteString -> Either UnpackError (T.Value t)+unpackValue bs =+  case Get.runGetOrFail unpackDecoder bs of     Left (_remainder, _offset, err) -> Left . UnpackError $ toText err     Right (_remainder, _offset, res) -> Right res  -- | Like 'unpackValue', for strict byte array. unpackValue'-  :: (SingI t, HasNoOp t, HasNoBigMap t)-  => UnpackEnv -> ByteString -> Either UnpackError (T.Value t)-unpackValue' env = unpackValue env . LBS.fromStrict+  :: (UnpackedValScope t)+  => ByteString -> Either UnpackError (T.Value t)+unpackValue' = unpackValue . LBS.fromStrict  -- | Overall value decoder we use in @UNPACK@. unpackDecoder-  :: (SingI t, HasNoOp t, HasNoBigMap t)-  => UnpackEnv -> Get (T.Value t)-unpackDecoder env =-  expectTag "Packed data start" 0x05 *> decodeValue env <* ensureEnd+  :: (UnpackedValScope t)+  => Get (T.Value t)+unpackDecoder =+  expectTag "Packed data start" 0x05 *> decodeValue <* ensureEnd  decodeValue   :: forall t.-     (SingI t, HasNoOp t, HasNoBigMap t)-  => UnpackEnv -> Get (T.Value t)-decodeValue env = Get.label "Value" $+     (HasCallStack, UnpackedValScope t)+  => Get (T.Value t)+decodeValue = Get.label "Value" $   case sing @t of     STc _ ->       T.VC <$> decodeCValue-    STKey ->-      decodeAsBytes $ do-        expectTag "Key pad" 0x00-        bs <- getByteStringCopy 32-        case mkPublicKey bs of-          Left err -> fail $ "Wrong public key format: " <> toString err-          Right pk -> pure (T.VKey pk)+    STKey -> T.VKey <$> asum+      [ decodeAsBytes $ decodeWithTag "key"+        [ TaggedDecoder 0x00 Ed25519.publicKeyLengthBytes+            (fmap PublicKeyEd25519 . Ed25519.mkPublicKey)+        , TaggedDecoder 0x01 Secp256k1.publicKeyLengthBytes+            (fmap PublicKeySecp256k1 . Secp256k1.mkPublicKey)+        , TaggedDecoder 0x02 P256.publicKeyLengthBytes+            (fmap PublicKeyP256 . P256.mkPublicKey)+        ]+      , decodeAsString parsePublicKey+      ]     STUnit -> do       expectDescTag "Unit" 0       expectTag "Unit" 0x0B       return T.VUnit-    STSignature -> do-      decodeAsBytes $ do-        bs <- getByteStringCopy 64-        case mkSignature bs of-          Left err -> fail $ "Wrong signature format: " <> toString err-          Right s -> pure (T.VSignature s)+    STSignature -> T.VSignature <$> asum+      [ decodeAsBytes $ \_len -> do -- TODO [TM-329]: ignoring length is bad+          bs <- getByteStringCopy signatureLengthBytes+          case mkSignature bs of+            -- We expect it to succeed because the length is+            -- exactly 'signatureLengthBytes'.+            Nothing -> error "mkSignature failed"+            Just s -> pure s+      , decodeAsString parseSignature+      ]+    STChainId -> asum+      [ decodeAsBytes $ \_len -> do -- TODO [TM-329]: ignoring length is bad+          bs <- getByteStringCopy chainIdLength+          case mkChainId bs of+            Nothing -> fail $ "Wrong chain id format"+            Just s -> pure (T.VChainId s)+      , T.VChainId <$> decodeAsString parseChainId+      ]     STOption _ -> do       Get.getByteString 2 >>= \case         "\x03\x06" -> pure (T.VOption Nothing)-        "\x05\x09" -> T.VOption . Just <$> decodeValue env+        "\x05\x09" -> T.VOption . Just <$> decodeValue         other -> fail $ "Unknown option tag: " <> show other     STList _ -> do-      decodeAsList $ T.VList <$> manyForced (decodeValue env)+      decodeAsList $ T.VList <$> manyForced decodeValue     STSet _ -> do       decodeAsList $ do         vals <- manyForced decodeCValue         either (fail . toString) pure $           T.VSet . Set.fromDistinctAscList <$> ensureDistinctAsc id vals-    STContract _ ->-      T.VContract <$> decodeAddress     STPair lt _ ->-      case (checkOpPresence lt, checkBigMapPresence lt) of-        (OpAbsent, BigMapAbsent) -> do+      case (checkOpPresence lt, checkBigMapPresence lt, checkContractTypePresence lt) of+        (OpAbsent, BigMapAbsent, ContractAbsent) -> do           expectDescTag "Pair" 2           expectTag "Pair" 0x07-          T.VPair ... (,) <$> decodeValue env <*> decodeValue env+          T.VPair ... (,) <$> decodeValue <*> decodeValue     STOr lt _ ->-      case (checkOpPresence lt, checkBigMapPresence lt) of-        (OpAbsent, BigMapAbsent) -> do+      case (checkOpPresence lt, checkBigMapPresence lt, checkContractTypePresence lt) of+        (OpAbsent, BigMapAbsent, ContractAbsent) -> do           expectDescTag "Or" 1           Get.getWord8 >>= \case-            0x05 -> T.VOr . Left <$> decodeValue env-            0x08 -> T.VOr . Right <$> decodeValue env+            0x05 -> T.VOr . Left <$> decodeValue+            0x08 -> T.VOr . Right <$> decodeValue             other -> unknownTag "or constructor" other     STLambda _ _ -> do-      uinstr <- decodeOps env-      T.VLam <$> decodeTypeCheckLam env uinstr+      uinstr <- decodeOps+      T.VLam <$> decodeTypeCheckLam uinstr     STMap _ _ -> do-      T.VMap <$> decodeMap env+      T.VMap <$> decodeMap  decodeCValue :: forall ct. SingI ct => Get (T.CValue ct) decodeCValue = case sing @ct of-  -- TODO [TM-140]: The reference implementation allows to decode some-  -- of cases below both from bytes and from string; consider this.   SCInt -> do     expectTag "Int" 0x00     T.CvInt <$> decodeInt@@ -266,16 +322,23 @@       0x0A -> pure (T.CvBool True)       0x03 -> pure (T.CvBool False)       other -> unknownTag "bool" other-  SCKeyHash ->-    decodeAsBytes $ do-      expectTag "key address pad" 0x00-      T.CvKeyHash . KeyHash <$> getByteStringCopy 20+  SCKeyHash -> T.CvKeyHash <$> asum+    [ decodeAsBytes $ decodeWithTag "key_hash" keyHashDecoders+    , decodeAsString parseKeyHash+    ]   SCTimestamp -> do     expectTag "Timestamp" 0x00-    T.CvTimestamp . timestampFromSeconds @Integer <$> decodeInt+    T.CvTimestamp . timestampFromSeconds <$> decodeInt   SCAddress ->-    T.CvAddress <$> decodeAddress+    T.CvAddress <$> decodeEpAddress +keyHashDecoders :: [TaggedDecoder KeyHash]+keyHashDecoders =+  [ TaggedDecoder @Void 0x00 keyHashLengthBytes (pure . KeyHash KeyHashEd25519)+  , TaggedDecoder @Void 0x01 keyHashLengthBytes (pure . KeyHash KeyHashSecp256k1)+  , TaggedDecoder @Void 0x02 keyHashLengthBytes (pure . KeyHash KeyHashP256)+  ]+ -- | Read length of something (list, string, ...). decodeLength :: Get Int decodeLength = Get.label "Length" $ do@@ -313,43 +376,61 @@     & either (fail . show) pure     ? "Michelson string validity analysis" +decodeAsString :: Buildable e => (Text -> Either e a) -> Get a+decodeAsString parser = do+  expectTag "String" 0x01+  str <- decodeString+  either (fail . pretty) pure $ parser $ unMText str+ decodeAsBytesRaw :: (Int -> Get a) -> Get a decodeAsBytesRaw decode = do   l <- decodeLength ? "Byte array length"   decode l ? "Byte array content" -decodeAsBytes :: Get a -> Get a+decodeAsBytes :: (Int -> Get a) -> Get a decodeAsBytes decode = do   expectTag "Bytes" 0x0A-  decodeAsBytesRaw (const decode)+  decodeAsBytesRaw decode  decodeBytes :: Get ByteString decodeBytes = decodeAsBytesRaw getByteStringCopy  decodeMap-  :: (SingI k, SingI v, HasNoOp v, HasNoBigMap v)-  => UnpackEnv -> Get $ Map (T.CValue k) (T.Value v)-decodeMap env = Get.label "Map" $+  :: (SingI k, UnpackedValScope v)+  => Get $ Map (T.CValue k) (T.Value v)+decodeMap = Get.label "Map" $   decodeAsList $ do     es <- manyForced $ do       expectDescTag "Elt" 2       expectTag "Elt" 0x04-      (,) <$> decodeCValue <*> decodeValue env+      (,) <$> decodeCValue <*> decodeValue     either (fail . toString) pure $       Map.fromDistinctAscList <$> ensureDistinctAsc fst es  decodeAddress :: Get Address-decodeAddress = Get.label "Address" $-  decodeAsBytes $ (Get.getWord8 ? "Address tag") >>= \case-    0x00 -> Get.label "Plain address" $ do-      expectTag "key address pad" 0x00-      KeyAddress . KeyHash <$> getByteStringCopy 20-    0x01 -> Get.label "Contract address" $ do-      addr <- getByteStringCopy 20-      expectTag "contract address pad" 0x00-      return $ ContractAddress addr-    other -> unknownTag "address" other+decodeAddress  = Get.label "Address" $ asum+  -- 1 byte is spent on tag specified here (0x00 or 0x01), so we subtract it.+  [ decodeAsBytes $ \(pred -> lenNoTag) -> decodeWithTagSimple "address"+    [ (0x00, KeyAddress <$>+        decodeWithTag "key_hash inside address" keyHashDecoders lenNoTag)+    , (0x01, Get.label "Contract addres" $ do+        -- TODO [TM-329]: ignoring length is bad+        addr <- getByteStringCopy 20+        expectTag "Contract address suffix" 0x00+        return $ ContractAddress (ContractHash addr)+      )+    ]+  , decodeAsString parseAddress+  ] +decodeEpAddress :: Get EpAddress+decodeEpAddress = do+  eaAddress <- decodeAddress+  refAnn <- decodeAnn+  eaEntryPoint <- epNameFromRefAnn refAnn+                & either (fail . pretty) pure+  return EpAddress{..}+ -- | Read a numeric value. decodeInt :: Num i => Get i decodeInt = fromIntegral @Integer <$> loop 0 0 ? "Number"@@ -379,18 +460,17 @@ decodeTypeCheckLam   :: forall inp out m.      (Typeable inp, SingI inp, SingI out, Typeable out, MonadFail m)-  => UnpackEnv-  -> [ExpandedOp]-  -> m (T.Instr '[inp] '[out])-decodeTypeCheckLam UnpackEnv{..} uinstr =+  => [ExpandedOp]+  -> m (RemFail T.Instr '[inp] '[out])+decodeTypeCheckLam uinstr =   either tcErrToFail pure . evaluatingState tcInitEnv . runExceptT $ do-    let inp = (sing @inp, T.NStar, noAnn) ::& SNil+    let inp = (sing @inp, starNotes, noAnn) ::& SNil     _ :/ instr' <- typeCheckList uinstr inp     case instr' of       instr ::: out' ->         case eqHST1 @out out' of           Right Refl ->-            pure instr+            pure $ RfNormal instr           Left err ->                 -- dummy types, we have no full information to build untyped                 -- 'T' anyway@@ -400,41 +480,52 @@               TCFailedOnInstr (LAMBDA noAnn tinp tout uinstr) (SomeHST inp)               "Unexpected lambda output type" def (Just err)       AnyOutInstr instr ->-        return instr+        return $ RfAlwaysFails instr   where     tcErrToFail err = fail $ "Type check failed: " +| err |+ ""     tcInitEnv =+      -- In Tezos @UNPACK@ instruction does not depend on environment.+      --+      -- We initialize each of the fields as 'error' (rather than just defining+      -- the whole datatype as 'error') to make source of error more obvious+      -- if access to one of these fields is performed after all.       TypeCheckEnv       { tcExtFrames = error "runInstrImpl(UNPACK): tcExtFrames touched"         --- ^ This is safe because @UNPACK@ never produces Ext instructions       , tcContractParam = error "runInstrImpl(UNPACK): tcContractParam touched"         --- ^ Used only in @SELF@ interpretation,         ---   but there is no way for @SELF@ to appear in packed data-      , tcContracts = ueContracts+      , tcContracts = error "runInstrImpl(UNPACK): tcContracts touched"+        --- ^ Used only in typechecking of @contract@ values,+        ---   but it's not possible to unpack to ones.       } -decodeInstr :: UnpackEnv -> Get ExpandedInstr-decodeInstr env = Get.label "Instruction" $ do+decodeInstr :: Get ExpandedInstr+decodeInstr = Get.label "Instruction" $ do   pretag <- Get.getWord8 ? "Pre instr tag"   tag <- Get.getWord8 ? "Instr tag"   case (pretag, tag) of     (0x03, 0x20) -> pure $ DROP+    (0x05, 0x20) -> DROPN <$> (expectTag "'DROP n' parameter" 0x00 *> decodeInt)     (0x03, 0x21) -> pure $ DUP noAnn     (0x03, 0x4C) -> pure $ SWAP+    (0x05, 0x70) -> DIG <$> (expectTag "'DIG n' parameter" 0x00 *> decodeInt)+    (0x05, 0x71) -> DUG <$> (expectTag "'DUG n' parameter" 0x00 *> decodeInt)     (0x07, 0x43) -> do       an :: VarAnn <- decodeAnn       typ <- decodeType       T.withSomeSingT (T.fromUType typ) $ \(st :: Sing t) ->-        case (opAbsense st, bigMapAbsense st) of-          (Nothing, _) -> fail "Operation type in PUSH"-          (_, Nothing) -> fail "BigMap type in PUSH"-          (Just Dict, Just Dict) -> do-            tval <- decodeValue @t env+        case (opAbsense st, bigMapAbsense st, contractTypeAbsense st) of+          (Nothing, _, _) -> fail "Operation type cannot appear in PUSH"+          (_, Nothing, _) -> fail "BigMap type cannot appear in PUSH"+          (_, _, Nothing) -> fail "'contract' type cannot appear in PUSH"+          (Just Dict, Just Dict, Just Dict) -> do+            tval <- decodeValue @t             return $ PUSH an typ (T.untypeValue tval)-    (0x03, 0x46) -> SOME <$> decodeAnn <*> decodeAnn <*> decodeAnn-    (0x05, 0x3E) -> NONE <$> decodeAnn <*> decodeAnn <*> decodeAnn <*> decodeType+    (0x03, 0x46) -> SOME <$> decodeAnn <*> decodeAnn+    (0x05, 0x3E) -> NONE <$> decodeAnn <*> decodeAnn <*> decodeType     (0x03, 0x4F) -> UNIT <$> decodeAnn <*> decodeAnn-    (0x07, 0x2F) -> IF_NONE <$> decodeOps env <*> decodeOps env+    (0x07, 0x2F) -> IF_NONE <$> decodeOps <*> decodeOps     (0x03, 0x42) -> PAIR <$> decodeAnn <*> decodeAnn <*> decodeAnn <*> decodeAnn     (0x03, 0x16) -> CAR <$> decodeAnn <*> decodeAnn     (0x03, 0x17) -> CDR <$> decodeAnn <*> decodeAnn@@ -442,29 +533,34 @@                          <*> decodeType     (0x05, 0x44) -> RIGHT <$> decodeAnn <*> decodeAnn <*> decodeAnn <*> decodeAnn                           <*> decodeType-    (0x07, 0x2E) -> IF_LEFT <$> decodeOps env <*> decodeOps env+    (0x07, 0x2E) -> IF_LEFT <$> decodeOps  <*> decodeOps     (0x05, 0x3D) -> NIL <$> decodeAnn <*> decodeAnn <*> decodeType     (0x03, 0x1B) -> CONS <$> decodeAnn-    (0x07, 0x2D) -> IF_CONS <$> decodeOps env <*> decodeOps env+    (0x07, 0x2D) -> IF_CONS <$> decodeOps  <*> decodeOps     (0x03, 0x45) -> SIZE <$> decodeAnn     (0x05, 0x24) -> EMPTY_SET <$> decodeAnn <*> decodeAnn <*> decodeComparable     (0x07, 0x23) -> EMPTY_MAP <$> decodeAnn <*> decodeAnn <*> decodeComparable                               <*> decodeType-    (0x05, 0x38) -> MAP <$> decodeAnn <*> decodeOps env-    (0x05, 0x52) -> ITER <$> decodeOps env+    (0x07, 0x72) -> EMPTY_BIG_MAP <$> decodeAnn <*> decodeAnn <*> decodeComparable+                                  <*> decodeType+    (0x05, 0x38) -> MAP <$> decodeAnn <*> decodeOps+    (0x05, 0x52) -> ITER <$> decodeOps     (0x03, 0x39) -> MEM <$> decodeAnn     (0x03, 0x29) -> GET <$> decodeAnn-    (0x03, 0x50) -> pure UPDATE-    (0x07, 0x2C) -> IF <$> decodeOps env <*> decodeOps env-    (0x05, 0x34) -> LOOP <$> decodeOps env-    (0x05, 0x53) -> LOOP_LEFT <$> decodeOps env+    (0x03, 0x50) -> UPDATE <$> decodeAnn+    (0x07, 0x2C) -> IF <$> decodeOps  <*> decodeOps+    (0x05, 0x34) -> LOOP <$> decodeOps+    (0x05, 0x53) -> LOOP_LEFT <$> decodeOps     (0x09, 0x31) -> do       res <- decodeAsListRaw $-        LAMBDA <$> decodeAnn <*> decodeType <*> decodeType <*> decodeOps env+        LAMBDA <$> decodeAnn <*> decodeType <*> decodeType <*> decodeOps       void decodeLength       return res     (0x03, 0x26) -> EXEC <$> decodeAnn-    (0x05, 0x1F) -> DIP <$> decodeOps env+    (0x03, 0x73) -> APPLY <$> decodeAnn+    (0x05, 0x1F) -> DIP <$> decodeOps+    (0x07, 0x1F) ->+      DIPN <$> (expectTag "'DIP n' parameter" 0x00 *> decodeInt) <*> decodeOps     (0x03, 0x27) -> pure FAILWITH     (0x05, 0x57) -> CAST <$> decodeAnn <*> decodeType     (0x03, 0x58) -> RENAME <$> decodeAnn@@ -478,7 +574,7 @@     (0x03, 0x3A) -> MUL <$> decodeAnn     (0x03, 0x22) -> EDIV <$> decodeAnn     (0x03, 0x11) -> ABS <$> decodeAnn-    (0x03, 0x3B) -> pure NEG+    (0x03, 0x3B) -> NEG <$> decodeAnn     (0x03, 0x35) -> LSL <$> decodeAnn     (0x03, 0x36) -> LSR <$> decodeAnn     (0x03, 0x41) -> OR <$> decodeAnn@@ -493,10 +589,10 @@     (0x03, 0x32) -> LE <$> decodeAnn     (0x03, 0x28) -> GE <$> decodeAnn     (0x03, 0x30) -> INT <$> decodeAnn-    (0x05, 0x55) -> CONTRACT <$> decodeAnn <*> decodeType+    -- TODO [TM-336]: consider field annotation here and lookup for entrypoint+    (0x05, 0x55) -> CONTRACT <$> decodeAnn <*> decodeAnn <*> decodeType     (0x03, 0x4D) -> TRANSFER_TOKENS <$> decodeAnn     (0x03, 0x4E) -> SET_DELEGATE <$> decodeAnn-    (0x03, 0x1C) -> CREATE_ACCOUNT <$> decodeAnn <*> decodeAnn     (0x05, 0x1D) ->       decodeAsList $ do         an1 <- decodeAnn@@ -509,7 +605,7 @@         s <- decodeType         expectTag "Pre contract code" 0x05         expectTag "Contract code" 0x02-        c <- decodeOps env+        c <- decodeOps         return $ CREATE_CONTRACT an1 an2 (Contract p s c)     (0x03, 0x1E) -> IMPLICIT_ACCOUNT <$> decodeAnn     (0x03, 0x40) -> NOW <$> decodeAnn@@ -524,18 +620,19 @@     (0x03, 0x47) -> SOURCE <$> decodeAnn     (0x03, 0x48) -> SENDER <$> decodeAnn     (0x03, 0x54) -> ADDRESS <$> decodeAnn+    (0x03, 0x75) -> CHAIN_ID <$> decodeAnn     (other1, other2) -> fail $ "Unknown instruction tag: 0x" +|                         hexF other1 |+ hexF other2 |+ "" -decodeOp :: UnpackEnv -> Get ExpandedOp-decodeOp env = Get.label "Op" $ do+decodeOp :: Get ExpandedOp+decodeOp = Get.label "Op" $ do   tag <- Get.lookAhead Get.getWord8   if tag == 0x02-    then SeqEx <$> decodeOps env ? "Ops seq"-    else PrimEx <$> decodeInstr env ? "One op"+    then SeqEx <$> decodeOps ? "Ops seq"+    else PrimEx <$> decodeInstr ? "One op" -decodeOps :: UnpackEnv -> Get [ExpandedOp]-decodeOps env = decodeAsList $ manyForced (decodeOp env)+decodeOps :: Get [ExpandedOp]+decodeOps = decodeAsList $ manyForced decodeOp  decodeComparable :: Get Comparable decodeComparable = Get.label "Comparable primitive type" $@@ -569,7 +666,8 @@         (0x03, 0x5C) -> pure TKey         (0x03, 0x6C) -> pure TUnit         (0x03, 0x67) -> pure TSignature-        (0x05, 0x63) -> TOption <$> decodeAnn <*> decodeType+        (0x03, 0x74) -> pure TChainId+        (0x05, 0x63) -> TOption <$> decodeType         (0x05, 0x5F) -> TList <$> decodeType         (0x05, 0x66) -> TSet <$> decodeComparable         (0x03, 0x6D) -> pure TOperation
src/Michelson/Macro.hs view
@@ -14,7 +14,6 @@   -- * Morley Parsed instruction types   , ParsedInstr   , ParsedOp (..)-  , ParsedUTestAssert   , ParsedUExtInstr      -- * For utilities@@ -37,7 +36,6 @@  import Data.Aeson.TH (defaultOptions, deriveJSON) import Data.Data (Data(..))-import Data.Generics (everywhere, mkT) import qualified Data.Text as T import Fmt (Buildable(build), genericF, (+|), (+||), (|+), (||+)) import qualified Text.PrettyPrint.Leijen.Text as PP (empty)@@ -46,6 +44,7 @@ import Michelson.Printer (RenderDoc(..)) import Michelson.Untyped import Util.Generic+import Util.Positive  -- | A programmer-defined macro data LetMacro = LetMacro@@ -84,7 +83,7 @@  -- dummy value instance RenderDoc ParsedOp where-  renderDoc _ = PP.empty+  renderDoc _ _ = PP.empty  instance Buildable ParsedOp where   build (Prim parseInstr _) = "<Prim: "+|parseInstr|+">"@@ -96,8 +95,6 @@ -- Types produced by parser ------------------------------------- -type ParsedUTestAssert = TestAssert ParsedOp- type ParsedUExtInstr = ExtInstrAbstract ParsedOp  type ParsedInstr = InstrAbstract ParsedOp@@ -108,6 +105,9 @@ data Macro   = CASE (NonEmpty [ParsedOp])   | TAG Natural (NonEmpty Type)+  | ACCESS Natural Positive+  | SET Natural Positive+  | CONSTRUCT (NonEmpty [ParsedOp])   | VIEW [ParsedOp]   | VOID [ParsedOp]   | CMP ParsedInstr VarAnn@@ -119,8 +119,8 @@   | CADR [CadrStruct] VarAnn FieldAnn   | SET_CADR [CadrStruct] VarAnn FieldAnn   | MAP_CADR [CadrStruct] VarAnn FieldAnn [ParsedOp]-  | DIIP Integer [ParsedOp]-  | DUUP Integer VarAnn+  | DIIP Word [ParsedOp]+  | DUUP Word VarAnn   | ASSERT   | ASSERTX ParsedInstr   | ASSERT_CMP ParsedInstr@@ -135,6 +135,9 @@ instance Buildable Macro where   build (TAG idx ty) = "<TAG: #"+||idx||+" from "+|toList ty|+""   build (CASE parsedInstrs) = "<CASE: "+|toList parsedInstrs|+">"+  build (ACCESS idx size) = "<ACCESS: #"+||idx||+"/"+|size|+""+  build (SET idx size) = "<SET: #"+||idx||+"/"+|size|+""+  build (CONSTRUCT parsedInstrs) = "<CONSTRUCT: "+|toList parsedInstrs|+">"   build (VIEW code) = "<VIEW: "+|code|+">"   build (VOID code) = "<VOID: "+|code|+">"   build (CMP parsedInstr carAnn) = "<CMP: "+|parsedInstr|+", "+|carAnn|+">"@@ -163,15 +166,7 @@  -- | Expand all macros in parsed contract. expandContract :: Contract' ParsedOp -> Contract-expandContract Contract {..} =-  Contract para stor (map (substituteTypes para stor) . expandList $ code)--substituteTypes :: Parameter -> Storage -> ExpandedOp -> ExpandedOp-substituteTypes param stor =-  everywhere $ mkT $ \case-    TypeParameter -> param-    TypeStorage -> stor-    t@(Type {}) -> t+expandContract Contract {..} = Contract para stor (expandList code)  -- Probably, some SYB can be used here expandValue :: ParsedValue -> Value@@ -192,35 +187,37 @@ expandElt (Elt l r) = Elt (expandValue l) (expandValue r)  expand :: LetCallStack -> ParsedOp -> ExpandedOp--- We handle this case specially, because it's essentially just PAIR.--- It's needed because we have a hack in parser: we parse PAIR as PAPAIR.--- We need to do something better eventually.-expand cs (Mac (PAPAIR (P (F a) (F b)) t v) pos) =-  WithSrcEx (InstrCallStack cs pos) $ PrimEx (PAIR t v (snd a) (snd b))-expand cs (Mac m pos)  = let ics = InstrCallStack cs pos in-  WithSrcEx ics $ SeqEx $ expandMacro ics m-expand cs (Prim i pos) = WithSrcEx (InstrCallStack cs pos) $ PrimEx $ expand cs <$> i-expand cs (Seq s pos)  = WithSrcEx (InstrCallStack cs pos) $ SeqEx $ expand cs <$> s-expand cs (LMac l pos) = expandLetMac l-  where-    expandLetMac :: LetMacro -> ExpandedOp-    expandLetMac LetMacro {..} =-      let newCS = LetName lmName : cs in-      let ics = InstrCallStack newCS pos in-      WithSrcEx ics $ PrimEx . EXT . FN lmName lmSig $ expand newCS <$> lmExpr+expand cs = let ics pos = InstrCallStack cs pos in \case+  -- We handle this case specially, because it's essentially just PAIR.+  -- It's needed because we have a hack in parser: we parse PAIR as PAPAIR.+  -- We need to do something better eventually.+  (Mac (PAPAIR (P (F a) (F b)) t v) pos) ->+    WithSrcEx (ics pos) $ PrimEx (PAIR t v (snd a) (snd b))+  -- DIIP is now always represented as a single instruction.+  -- `expandMacro` always returns a list which we wrap into `SeqEx`, so we+  -- can't use it.+  -- As the above comment says, we need to do something better eventually+  -- (e. g. to avoid `error` usage inside `expandMacro`).+  (Mac (DIIP n ops) pos) ->+    WithSrcEx (ics pos) $ PrimEx (DIPN n (expand cs <$> ops))+  (Mac m pos) -> WithSrcEx (ics pos) $ SeqEx $ expandMacro (ics pos) m+  (Prim i pos) -> WithSrcEx (ics pos) $ PrimEx $ expand cs <$> i+  (Seq s pos) -> WithSrcEx (ics pos) $ SeqEx $ expand cs <$> s+  (LMac l pos) -> expandLetMac l+    where+      expandLetMac :: LetMacro -> ExpandedOp+      expandLetMac LetMacro {..} =+        let newCS = LetName lmName : cs in+        let ics' = InstrCallStack newCS pos in+        WithSrcEx ics' $ PrimEx . EXT . FN lmName lmSig $ expand newCS <$> lmExpr  expandMacro :: InstrCallStack -> Macro -> [ExpandedOp] expandMacro p@InstrCallStack{icsCallStack=cs,icsSrcPos=macroPos} = \case   VIEW a             -> expandMacro p (UNPAIR $ P (F (noAnn,noAnn)) (F (noAnn,noAnn))) ++-                        [ PrimEx (DIP $ expandMacro p $ DUUP 2 noAnn)-                        , PrimEx $ DUP noAnn-                        , PrimEx $ DIP $ concat [-                              [PrimEx $ PAIR noAnn noAnn noAnn noAnn]-                            , expand cs <$> a-                            , [PrimEx $ SOME noAnn noAnn noAnn]-                            ]-                        , PrimEx $ PAIR noAnn noAnn noAnn noAnn-                        , PrimEx (DIP [PrimEx $ AMOUNT noAnn])+                        [ PrimEx (DIP $ expandMacro p $ DUUP 2 noAnn) ] +++                        [ PrimEx $ PAIR noAnn noAnn noAnn noAnn ] +++                        (expand cs <$> a) +++                        [ PrimEx (DIP [PrimEx $ AMOUNT noAnn])                         , PrimEx $ TRANSFER_TOKENS noAnn                         , PrimEx $ NIL noAnn noAnn (Type TOperation noAnn)                         , PrimEx $ SWAP@@ -234,9 +231,11 @@                         , PrimEx $ EXEC noAnn                         , PrimEx FAILWITH                         ]-  CASE is            -> mkGenericTree (\_ l r -> one . PrimEx $ IF_LEFT l r)-                                      (map (expand cs) <$> is)-  TAG idx uty        -> expandTag (fromIntegral idx) uty+  CASE ops           -> expandCase (map (expand cs) <$> ops)+  TAG idx uty        -> expandTag idx uty+  ACCESS idx size    -> expandAccess idx size+  SET idx size       -> expandSet idx size+  CONSTRUCT ops      -> expandConstruct (map (expand cs) <$> ops)   CMP i v            -> [PrimEx (COMPARE v), xo i]   IFX i bt bf        -> [xo i, PrimEx $ IF (xp bt) (xp bf)]   IFCMP i v bt bf    -> PrimEx <$> [COMPARE v, expand cs <$> i, IF (xp bt) (xp bf)]@@ -255,10 +254,11 @@   CADR c v f         -> expandCadr p c v f   SET_CADR c v f     -> expandSetCadr p c v f   MAP_CADR c v f ops -> expandMapCadr p c v f ops-  DIIP 1 ops         -> oprimEx $ DIP (xp ops)-  DIIP n ops         -> oprimEx $ DIP $ expandMacro p (DIIP (n - 1) ops)-  DUUP 1 v           -> oprimEx $ DUP v-  DUUP n v           -> PrimEx <$> [DIP (expandMacro p (DUUP (n - 1) v)), SWAP]+  -- We handle DIIP outside.+  DIIP {}             -> error "expandMacro DIIP is unreachable"+  DUUP 1 v           -> oprimEx $ DUP v -- this case should be impossible in practice+  DUUP 2 v           -> PrimEx <$> [DIP [PrimEx $ DUP v], SWAP]+  DUUP n v           -> PrimEx <$> [DIPN (n - 1) [PrimEx $ DUP v], DIG n]   where     mac = flip Mac macroPos     oprimEx = one . PrimEx@@ -347,7 +347,10 @@   A:css -> PrimEx <$> [DUP noAnn, DIP (PrimEx carNoAnn : expandMacro ics (MAP_CADR css noAnn f ops)), cdrNoAnn, SWAP, pairNoAnn v]   D:css -> PrimEx <$> [DUP noAnn, DIP (PrimEx cdrNoAnn : expandMacro ics (MAP_CADR css noAnn f ops)), carNoAnn, pairNoAnn v] -expandTag :: Int -> NonEmpty Type -> [ExpandedOp]+expandCase :: NonEmpty [ExpandedOp] -> [ExpandedOp]+expandCase = mkGenericTree (\_ l r -> one . PrimEx $ IF_LEFT l r)++expandTag :: Natural -> NonEmpty Type -> [ExpandedOp] expandTag idx unionTy =   reverse . fst $ mkGenericTree merge (([], ) <$> unionTy)   where@@ -356,6 +359,51 @@       in if idx < i           then (PrimEx (LEFT noAnn noAnn noAnn noAnn rt) : li, ty)           else (PrimEx (RIGHT noAnn noAnn noAnn noAnn lt) : ri, ty)++expandAccess :: Natural -> Positive -> [ExpandedOp]+expandAccess idx size =+  mkGenericTree merge (replicateNE size [])+  where+    merge i li ri =+      if idx < i+        then PrimEx (CAR noAnn noAnn) : li+        else PrimEx (CDR noAnn noAnn) : ri++expandSet :: Natural -> Positive -> [ExpandedOp]+expandSet idx size =+  PrimEx <$>+  appEndo (mkGenericTree merge (replicateNE size base)) []+  where+    base = pre $ DIP [PrimEx DROP]+    merge i li ri = mconcat $+      if idx < i+        then [ pre $ DIP+                 (map PrimEx [DUP n, DIP [PrimEx $ CDR n n], CAR n n])+             , li+             , pre $ PAIR n n n n+             ]+        else [ pre $ DIP+                 (map PrimEx [DUP n, DIP [PrimEx $ CAR n n], CDR n n])+             , ri+             , pre $ SWAP+             , pre $ PAIR n n n n+             ]+    pre e = Endo (e :)+    n = noAnn++expandConstruct :: NonEmpty [ExpandedOp] -> [ExpandedOp]+expandConstruct ctors =+  appEndo (mkGenericTree merge $ map toBase ctors) []+  where+    toBase ops = Endo (ops ++)+    merge _ li ri =+      mconcat+        [ li+        , pre . PrimEx $ DIP (appEndo ri [])+        , pre . PrimEx $ PAIR noAnn noAnn noAnn noAnn+        ]+    pre e = Endo (e :)+  mapLeaves :: [(VarAnn, FieldAnn)] -> PairStruct -> PairStruct mapLeaves fs p = evalState (leavesST p) fs
+ src/Michelson/OpSize.hs view
@@ -0,0 +1,241 @@+-- | Measuring operation size.+--+-- When originating a contract or making a transfer, tezos node forms operation+-- which is submitted over network. Size of this operation depends on content+-- of originated contract or transfer parameter resp., and tezos has a hard+-- limit on operation size thus it has to be accounted.+--+-- Functions declared in this module allow assessing size of origination or+-- transfer operation with up to constant precision because it yet accounts only+-- for Michelson primitives participating in the operation.+-- Other stuff which affects op size include parameters which user passes to+-- origination or transfer themselves, for instance, amount of mutez carried+-- to the contract. ATM we don't have necessary primitives in Haskell to be+-- able to handle those parameters here, probably waiting for [TM-89].+-- Currently, we can assess overall transfer size only approximatelly, like+-- in 'smallTransferOpSize'.+module Michelson.OpSize+  ( OpSize (..)+  , opSizeHardLimit+  , smallTransferOpSize+  , instrOpSize+  , expandedInstrsOpSize+  , valueOpSize+  ) where++import Prelude hiding (Ordering(..))++import Michelson.Interpret.Pack+import Michelson.Untyped++-- | Operation size in bytes.+--+-- We use newtype wrapper because there are different units of measure+-- (another one is gas, and we don't want to confuse them).+newtype OpSize = OpSize { unOpSize :: Word }+  deriving (Show, Eq, Ord)++instance Semigroup OpSize where+  OpSize a <> OpSize b = OpSize (a + b)+instance Monoid OpSize where+  mempty = OpSize 0++-- | Maximal operation size allowed by Tezos production nodes.+opSizeHardLimit :: OpSize+opSizeHardLimit = OpSize 16384++-- | Base cost of any transfer of 0 mutez with no extra parameters.+-- (Add 'valueOpSize <param>' to it to get assessment of actual transfer op size)+smallTransferOpSize :: OpSize+smallTransferOpSize = OpSize 162++instrOpSize :: InstrAbstract ExpandedOp -> OpSize+instrOpSize = (OpSize 2 <>) . \case+  EXT{} -> mempty+  DROPN n -> stackDepthOpSize n+  DROP -> mempty+  DUP va -> annsOpSize va+  SWAP -> mempty+  DIG n -> stackDepthOpSize n+  DUG n -> stackDepthOpSize n+  PUSH va t v -> annsOpSize va <> typeOpSize t <> valueOpSize v+  SOME ta va -> annsOpSize ta va+  NONE ta va t -> annsOpSize ta va <> typeOpSize t+  UNIT ta va -> annsOpSize ta va+  IF_NONE l r -> ifOpSize l r+  PAIR ta va fal far -> annsOpSize ta va fal far+  CAR va fa -> annsOpSize va fa+  CDR va fa -> annsOpSize va fa+  LEFT ta va fal far t -> annsOpSize ta va fal far <> typeOpSize t+  RIGHT ta va fal far t -> annsOpSize ta va fal far <> typeOpSize t+  IF_LEFT l r -> ifOpSize l r+  NIL ta va t -> annsOpSize ta va <> typeOpSize t+  CONS va -> annsOpSize va+  IF_CONS l r -> ifOpSize l r+  SIZE va -> annsOpSize va+  EMPTY_SET ta va ct -> annsOpSize ta va <> comparableOpSize ct+  EMPTY_MAP ta va ct t -> annsOpSize ta va <> comparableOpSize ct <> typeOpSize t+  EMPTY_BIG_MAP ta va ct t -> annsOpSize ta va <> comparableOpSize ct <> typeOpSize t+  MAP va is -> annsOpSize va <> subcodeOpSize is+  ITER is -> annsOpSize <> subcodeOpSize is+  MEM va -> annsOpSize va+  GET va -> annsOpSize va+  UPDATE va -> annsOpSize va+  IF l r -> ifOpSize l r+  LOOP is -> expandedInstrsOpSize is+  LOOP_LEFT is -> expandedInstrsOpSize is+  LAMBDA va ti to is ->+    annsOpSize va <> typeOpSize ti <> typeOpSize to <> expandedInstrsOpSize is+  EXEC va -> annsOpSize va+  APPLY va -> annsOpSize va+  DIP is -> subcodeOpSize is+  DIPN n is -> stackDepthOpSize n <> subcodeOpSize is+  FAILWITH -> mempty+  CAST va t -> annsOpSize va <> typeOpSize t+  RENAME va -> annsOpSize va+  PACK va -> annsOpSize va+  UNPACK va t -> annsOpSize va <> typeOpSize t+  CONCAT va -> annsOpSize va+  SLICE va -> annsOpSize va+  ISNAT va -> annsOpSize va+  ADD va -> annsOpSize va+  SUB va -> annsOpSize va+  MUL va -> annsOpSize va+  EDIV va -> annsOpSize va+  ABS va -> annsOpSize va+  NEG va -> annsOpSize va+  LSL va -> annsOpSize va+  LSR va -> annsOpSize va+  OR va -> annsOpSize va+  AND va -> annsOpSize va+  XOR va -> annsOpSize va+  NOT va -> annsOpSize va+  COMPARE va -> annsOpSize va+  EQ va -> annsOpSize va+  NEQ va -> annsOpSize va+  LT va -> annsOpSize va+  LE va -> annsOpSize va+  GT va -> annsOpSize va+  GE va -> annsOpSize va+  INT va -> annsOpSize va+  SELF va -> annsOpSize va+  CONTRACT va fa t -> annsOpSize va fa <> typeOpSize t+  TRANSFER_TOKENS va -> annsOpSize va+  SET_DELEGATE va -> annsOpSize va+  CREATE_CONTRACT va1 va2 c -> annsOpSize va1 va2 <> contractOpSize c+  IMPLICIT_ACCOUNT va -> annsOpSize va+  NOW va -> annsOpSize va+  AMOUNT va -> annsOpSize va+  BALANCE va -> annsOpSize va+  CHECK_SIGNATURE va -> annsOpSize va+  SHA256 va -> annsOpSize va+  SHA512 va -> annsOpSize va+  BLAKE2B va -> annsOpSize va+  HASH_KEY va -> annsOpSize va+  STEPS_TO_QUOTA va -> annsOpSize va+  SOURCE va -> annsOpSize va+  SENDER va -> annsOpSize va+  ADDRESS va -> annsOpSize va+  CHAIN_ID va -> annsOpSize va+  where+    subcodeOpSize is = expandedInstrOpSize (SeqEx is)+    ifOpSize l r = expandedInstrOpSize (SeqEx l) <> expandedInstrOpSize (SeqEx r)+    stackDepthOpSize n = OpSize 1 <> numOpSize n++expandedInstrOpSize :: ExpandedOp -> OpSize+expandedInstrOpSize = \case+  PrimEx i -> instrOpSize i+  SeqEx is -> OpSize 5 <> expandedInstrsOpSize is+  WithSrcEx _ i -> expandedInstrOpSize i++expandedInstrsOpSize :: [ExpandedOp] -> OpSize+expandedInstrsOpSize = foldMap expandedInstrOpSize++contractOpSize :: Contract -> OpSize+contractOpSize (Contract cp st is) =+  OpSize 16 <> typeOpSize cp <> typeOpSize st <> expandedInstrsOpSize is++numOpSize :: Integral i => i -> OpSize+numOpSize = OpSize . fromIntegral . length . encodeIntPayload . fromIntegral++valueOpSize :: Value -> OpSize+valueOpSize = (OpSize 1 <>) . \case+  ValueInt i -> numOpSize i+  ValueString s -> (seqOpSize <>) . OpSize . fromIntegral $ length s+  ValueBytes (InternalByteString b) -> (seqOpSize <>) . OpSize . fromIntegral $ length b+  ValueUnit -> baseOpSize+  ValueTrue -> baseOpSize+  ValueFalse -> baseOpSize+  ValuePair l r -> baseOpSize <> valueOpSize l <> valueOpSize r+  ValueLeft x -> baseOpSize <> valueOpSize x+  ValueRight x -> baseOpSize <> valueOpSize x+  ValueSome x -> baseOpSize <> valueOpSize x+  ValueNone -> baseOpSize+  ValueNil -> seqOpSize+  ValueSeq l -> seqOpSize <> foldMap valueOpSize l+  ValueMap m -> seqOpSize <> foldMap eltOpSize m+  ValueLambda m -> seqOpSize <> foldMap expandedInstrOpSize m+  where+    baseOpSize = OpSize 1+    seqOpSize = OpSize 4+    eltOpSize (Elt k v) = OpSize 2 <> valueOpSize k <> valueOpSize v++typeOpSize :: Type -> OpSize+typeOpSize = typeOpSize' []++typeOpSize' :: [FieldAnn] -> Type -> OpSize+typeOpSize' anns (Type t ta) =+  tOpSize t <> annsOpSize ta anns++tOpSize :: T -> OpSize+tOpSize = \case+  Tc ct -> ctOpSize ct+  TKey -> baseOpSize+  TUnit -> baseOpSize+  TSignature -> baseOpSize+  TChainId -> baseOpSize+  TOption a -> baseOpSize <> typeOpSize a+  TList a -> baseOpSize <> typeOpSize a+  TSet a -> baseOpSize <> comparableOpSize a+  TOperation -> baseOpSize+  TContract a -> baseOpSize <> typeOpSize a+  TPair al ar l r -> baseOpSize <> typeOpSize' [al] l <> typeOpSize' [ar] r+  TOr al ar l r -> baseOpSize <> typeOpSize' [al] l <> typeOpSize' [ar] r+  TLambda i o -> baseOpSize <> typeOpSize i <> typeOpSize o+  TMap k v -> baseOpSize <> comparableOpSize k <> typeOpSize v+  TBigMap k v -> baseOpSize <> comparableOpSize k <> typeOpSize v+  where+    -- TODO: use this once in the function beginning (and inline it) once 'CT'+    -- and 'Comparable' are gone+    baseOpSize = OpSize 2++comparableOpSize :: Comparable -> OpSize+comparableOpSize (Comparable ct a) =+  ctOpSize ct <> annsOpSize a++ctOpSize :: CT -> OpSize+ctOpSize _ = OpSize 2++-- | Accepts arbitrary number of 'Annotation's (maybe of different types)+-- which belong to the same entity and returns their total operation size.+--+-- Note that annotations which belong to the same entity (type or instruction)+-- __must be__ considered in aggregate using one call of this function.+annsOpSize :: AnnsOpSizeVararg x => x+annsOpSize = annsOpSizeVararg []++class AnnsOpSizeVararg x where+  annsOpSizeVararg :: [SomeAnn] -> x++instance AnnsOpSizeVararg x => AnnsOpSizeVararg (Annotation t -> x) where+  annsOpSizeVararg acc an = annsOpSizeVararg (convAnn an : acc)+instance AnnsOpSizeVararg x => AnnsOpSizeVararg ([Annotation t] -> x) where+  annsOpSizeVararg acc an = annsOpSizeVararg (map convAnn an <> acc)++instance AnnsOpSizeVararg OpSize where+  annsOpSizeVararg = annsOpSizeImpl++annsOpSizeImpl :: [SomeAnn] -> OpSize+annsOpSizeImpl anns = case filter (/= noAnn) anns of+  [] -> mempty+  as -> OpSize . fromIntegral $ 3 * (length as + 1)
+ src/Michelson/Optimizer.hs view
@@ -0,0 +1,296 @@+-- | Optimizer for typed instructions.+--+-- It's quite experimental and incomplete.+-- List of possible improvements:+-- 1. 'pushDrop', 'dupDrop', 'unitDrop' rules are essentially the+-- same. It would be good to generalize them into one rule. The same+-- applies to 'pushDip'.+-- It probably can be done more efficiently.++module Michelson.Optimizer+  ( optimize+  , optimizeWithConf+  , defaultRules+  , defaultRulesAndPushPack+  , orRule+  , orSimpleRule+  , Rule+  , OptimizerConf (..)+  ) where++import Prelude hiding (EQ)++import Data.Default (Default(def))++import Michelson.Interpret.Pack (packValue')+import Michelson.Typed.Aliases (Value)+import Michelson.Typed.CValue+import Michelson.Typed.Instr+import Michelson.Typed.Scope (PackedValScope)+import Michelson.Typed.T+import Michelson.Typed.Util (DfsSettings(..), dfsInstr)+import Michelson.Typed.Value+import Util.Peano (Sing(..))++----------------------------------------------------------------------------+-- High level+----------------------------------------------------------------------------++data OptimizerConf = OptimizerConf+  { gotoValues :: Bool+  , ruleset    :: Rule -> Rule+  }++instance Default OptimizerConf where+  def = OptimizerConf+    { gotoValues = False+    , ruleset    = defaultRules+    }++-- | Optimize a typed instruction by replacing some sequences of+-- instructions with smaller equivalent sequences.+-- Applies default set of rewrite rules.+optimize :: Instr inp out -> Instr inp out+optimize = optimizeWithConf def++-- | Optimize a typed instruction using a custom set of rules.+optimizeWithConf :: OptimizerConf -> Instr inp out -> Instr inp out+optimizeWithConf (OptimizerConf gotoValues rules)+  = (fst .)+  $ dfsInstr dfsSettings+  $ (adapter .)+  $ applyOnce+  $ fixpoint rules+  where+    dfsSettings = def{ dsGoToValues = gotoValues }++----------------------------------------------------------------------------+-- Rewrite rules+----------------------------------------------------------------------------++-- Type of a single rewrite rule. It takes an instruction and tries to+-- optimize its head (first few instructions).  If optimization+-- succeeds, it returns `Just` the optimized instruction, otherwise it+-- returns `Nothing`.+type Rule = forall inp out. Instr inp out -> Maybe (Instr inp out)++defaultRules :: Rule -> Rule+defaultRules =+  flattenSeqLHS+    `orSimpleRule` removeNesting+    `orSimpleRule` dipDrop2swapDrop+    `orSimpleRule` ifNopNop2Drop+    `orSimpleRule` nopIsNeutralForSeq+    `orSimpleRule` variousNops+    `orSimpleRule` dupSwap2dup+    `orSimpleRule` noDipNeeded+    `orSimpleRule` branchShortCut+    `orSimpleRule` compareWithZero+    `orSimpleRule` simpleDrops+    `orSimpleRule` internalNop+    `orSimpleRule` simpleDips++-- | We do not enable 'pushPack' rule by default because it is+-- potentially dangerous.+-- There are various code processing functions that may depend on constants,+-- e. g. string transformations.+defaultRulesAndPushPack :: Rule -> Rule+defaultRulesAndPushPack = defaultRules `orSimpleRule` pushPack++flattenSeqLHS :: Rule -> Rule+flattenSeqLHS toplevel = \case+  it@(Seq (Seq _ _) _) -> Just $ linearizeAndReapply toplevel it+  _                    -> Nothing++removeNesting :: Rule+removeNesting = \case+  Nested i -> Just i+  _        -> Nothing++dipDrop2swapDrop :: Rule+dipDrop2swapDrop = \case+  DIP DROP -> Just $ Seq SWAP DROP+  _        -> Nothing++ifNopNop2Drop :: Rule+ifNopNop2Drop = \case+  IF Nop Nop -> Just DROP+  _          -> Nothing++nopIsNeutralForSeq :: Rule+nopIsNeutralForSeq = \case+  Seq Nop i  -> Just i+  Seq i Nop  -> Just i+  _          -> Nothing++variousNops :: Rule+variousNops = \case+  Seq  SWAP    (Seq SWAP c) -> Just c+  Seq (PUSH _) (Seq DROP c) -> Just c+  Seq  DUP     (Seq DROP c) -> Just c+  Seq  UNIT    (Seq DROP c) -> Just c+  Seq  SWAP         SWAP    -> Just Nop+  Seq (PUSH _)      DROP    -> Just Nop+  Seq  DUP          DROP    -> Just Nop+  Seq  UNIT         DROP    -> Just Nop+  _                         -> Nothing++dupSwap2dup :: Rule+dupSwap2dup = \case+  Seq DUP (Seq SWAP c) -> Just (Seq DUP c)+  Seq DUP      SWAP    -> Just      DUP+  _                    -> Nothing++noDipNeeded :: Rule+noDipNeeded = \case+  -- If we put a constant value on stack and then do something under it,+  -- we can do this "something" on original stack and then put that constant.+  Seq (PUSH x) (Seq (DIP f) c) -> Just (Seq f (Seq (PUSH x) c))+  Seq (PUSH x)      (DIP f)    -> Just (Seq f      (PUSH x))+  Seq UNIT     (Seq (DIP f) c) -> Just (Seq f (Seq UNIT c))+  Seq UNIT          (DIP f)    -> Just (Seq f      UNIT)++  -- If we do something ignoring top of the stack and then immediately+  -- drop top of the stack, we can drop that item in advance and+  -- not use 'DIP' at all.+  Seq (DIP f) (Seq DROP c)     -> Just (Seq DROP (Seq f c))+  Seq (DIP f) DROP             -> Just (Seq DROP f)++  _                            -> Nothing++branchShortCut :: Rule+branchShortCut = \case+  Seq LEFT  (Seq (IF_LEFT f _) c) -> Just (Seq f c)+  Seq RIGHT (Seq (IF_LEFT _ f) c) -> Just (Seq f c)+  Seq CONS  (Seq (IF_CONS f _) c) -> Just (Seq f c)+  Seq NIL   (Seq (IF_CONS _ f) c) -> Just (Seq f c)+  Seq NONE  (Seq (IF_NONE f _) c) -> Just (Seq f c)+  Seq SOME  (Seq (IF_NONE _ f) c) -> Just (Seq f c)++  Seq (PUSH (VC (CvBool True)))  (Seq (IF f _) c) -> Just (Seq f c)+  Seq (PUSH (VC (CvBool False))) (Seq (IF _ f) c) -> Just (Seq f c)++  Seq LEFT       (IF_LEFT f _)    -> Just f+  Seq RIGHT      (IF_LEFT _ f)    -> Just f+  Seq CONS       (IF_CONS f _)    -> Just f+  Seq NIL        (IF_CONS _ f)    -> Just f+  Seq NONE       (IF_NONE f _)    -> Just f+  Seq SOME       (IF_NONE _ f)    -> Just f++  Seq (PUSH (VC (CvBool True)))  (IF f _) -> Just f+  Seq (PUSH (VC (CvBool False))) (IF _ f) -> Just f++  _ -> Nothing++compareWithZero :: Rule+compareWithZero = \case+  Seq (PUSH (VC (CvInt 0))) (Seq COMPARE (Seq EQ c)) -> Just          (Seq EQ c)+  Seq (PUSH (VC (CvNat 0))) (Seq COMPARE (Seq EQ c)) -> Just (Seq INT (Seq EQ c))+  Seq (PUSH (VC (CvInt 0))) (Seq COMPARE      EQ)    -> Just               EQ+  Seq (PUSH (VC (CvNat 0))) (Seq COMPARE      EQ)    -> Just (Seq INT      EQ)+  _                                                  -> Nothing++simpleDrops :: Rule+simpleDrops = \case+  -- DROP 0 is Nop+  Seq (DROPN SZ) c -> Just c+  DROPN SZ -> Just Nop++  -- DROP 1 is DROP.+  -- @gromak: DROP seems to be cheaper (in my experiments it consumed 3 less gas).+  -- It is packed more efficiently.+  -- Unfortunately I do not know how to convince GHC that types match here.+  -- Specifically, it can not deduce that `inp` is not empty+  -- (`DROP` expects non-empty input).+  -- We have `LongerOrSameLength inp (S Z)` here, but that is not enough to+  -- convince GHC.+  -- I will leave this note and rule here in hope that someone will manage to+  -- deal with this problem one day.++  -- Seq (DROPN (SS SZ)) c -> Just (Seq DROP c)+  -- DROPN (SS SZ) -> Just DROP++  _ -> Nothing++-- If an instruction takes another instruction as an argument and that+-- internal instruction is 'Nop', sometimes the whole instruction is+-- 'Nop'.+-- For now we do it only for 'DIP', but ideally we should do it for+-- 'MAP' as well (which is harder).+internalNop :: Rule+internalNop = \case+  DIP Nop -> Just Nop+  Seq (DIP Nop) c -> Just c++  _ -> Nothing++simpleDips :: Rule+simpleDips = \case+  -- DIP 0 is redundant+  Seq (DIPN SZ i) c -> Just (Seq i c)+  DIPN SZ i -> Just i++  -- @gromak: same situation as with `DROP 1` (see above).+  -- Seq (DIPN (SS SZ) i) c -> Just (Seq (DIP i) c)+  -- DIPN (SS SZ) i -> Just (DIP i)++  _ -> Nothing++pushPack :: Rule+pushPack = \case+  Seq (PUSH x) PACK -> Just (pushPacked x)+  Seq (PUSH x) (Seq PACK c) -> Just (pushPacked x `Seq` c)++  _ -> Nothing+  where+    pushPacked :: PackedValScope t => Value t -> Instr s ('Tc 'CBytes ': s)+    pushPacked = PUSH . VC . CvBytes . packValue'++-- | Append LHS of 'Seq' to RHS and re-run pointwise ruleset at each point.+--   That might cause reinvocation of this function (see 'defaultRules'),+--   but productivity ensures it will flatten any 'Seq'-tree right-to-left,+--   while evaling no more than once on each node.+--+--   The reason this function invokes ruleset is when you append an instr+--   to already-optimised RHS of 'Seq', you might get an optimisable tree.+--+--   The argument is a local, non-structurally-recursive ruleset.+linearizeAndReapply :: Rule -> Instr inp out -> Instr inp out+linearizeAndReapply restart = \case+  Seq (Seq a b) c ->+    applyOnce restart $ Seq a (linearizeAndReapply restart (Seq b c))++  other -> other++----------------------------------------------------------------------------+-- Generic functions working with rules+----------------------------------------------------------------------------++-- | Combine two rule fixpoints.+orRule :: (Rule -> Rule) -> (Rule -> Rule) -> (Rule -> Rule)+orRule l r topl x = l topl x <|> r topl x++-- | Combine a rule fixpoint and a simple rule.+orSimpleRule :: (Rule -> Rule) -> Rule -> (Rule -> Rule)+orSimpleRule l r topl x = l topl x <|> r x++-- | Turn rule fixpoint into rule.+fixpoint :: (Rule -> Rule) -> Rule+fixpoint r = go+  where+    go :: Rule+    go = whileApplies (r go)++-- | Apply the rule once, if it fails, return the instruction unmodified.+applyOnce :: Rule -> Instr inp out -> Instr inp out+applyOnce r i = maybe i id (r i)++-- | An adapter for `dfsInstr`.+adapter :: a -> (a, ())+adapter a = (a, ())++-- | Apply a rule to the same code, until it fails.+whileApplies :: Rule -> Rule+whileApplies r = go+  where+    go i = maybe (Just i) go (r i)
src/Michelson/Parser.hs view
@@ -14,11 +14,12 @@    -- * Additional helpers   , parseNoEnv+  , parseValue+  , parseExpandValue    -- * For tests   , codeEntry   , type_-  , explicitType   , letType   , stringLiteral   , bytesLiteral@@ -29,11 +30,11 @@ import Prelude hiding (try)  import Control.Applicative.Permutations (intercalateEffect, toPermutation)-import Text.Megaparsec (Parsec, choice, eitherP, getSourcePos, parse, try)+import Text.Megaparsec (Parsec, choice, eitherP, eof, getSourcePos, lookAhead, parse, try) import Text.Megaparsec.Pos (SourcePos(..), unPos)  import Michelson.ErrorPos (SrcPos(..), mkPos)-import Michelson.Macro (LetMacro, Macro(..), ParsedInstr, ParsedOp(..), ParsedValue)+import Michelson.Macro (LetMacro, Macro(..), ParsedInstr, ParsedOp(..), ParsedValue, expandValue) import Michelson.Parser.Error import Michelson.Parser.Ext import Michelson.Parser.Instr@@ -44,6 +45,7 @@ import Michelson.Parser.Types import Michelson.Parser.Value import Michelson.Untyped+import qualified Michelson.Untyped as U  ---------------------------------------------------------------------------- -- Helpers@@ -55,7 +57,7 @@   -> String   -> Text   -> Either (ParseErrorBundle Text CustomParserException) a-parseNoEnv p = parse (runReaderT p noLetEnv)+parseNoEnv p = parse (runReaderT p noLetEnv <* eof)  ------------------------------------------------------------------------------- -- Parsers@@ -66,7 +68,7 @@  -- | Michelson contract with let definitions program :: Parsec CustomParserException Text (Contract' ParsedOp)-program = runReaderT programInner noLetEnv+program = runReaderT programInner noLetEnv <* eof   where     programInner :: Parser (Contract' ParsedOp)     programInner = do@@ -78,17 +80,19 @@ contract :: Parser (Contract' ParsedOp) contract = do   mSpace-  (p,s,c) <- intercalateEffect semicolon $-              (,,) <$> toPermutation parameter-                   <*> toPermutation storage-                   <*> toPermutation code+  (p,s,c) <- braces contractTuple <|> contractTuple   return $ Contract p s c   where+    contractTuple = intercalateEffect semicolon $+                     (,,) <$> toPermutation parameter+                          <*> toPermutation storage+                          <*> toPermutation code+     parameter :: Parser Type-    parameter = symbol "parameter" *> explicitType+    parameter = symbol "parameter" *> type_      storage :: Parser Type-    storage = symbol "storage" *> explicitType+    storage = symbol "storage" *> type_      code :: Parser [ParsedOp]     code = symbol "code" *> codeEntry@@ -100,7 +104,16 @@ value :: Parser ParsedValue value = value' parsedOp +-- | Parse untyped value from text which comes from something that is+-- not a file (which is often the case). So we assume it does not need+-- any parsing environment.+parseValue :: Text -> Either ParserException ParsedValue+parseValue = first ParserException . parseNoEnv value "" +-- | Like 'parseValue', but also expands macros.+parseExpandValue :: Text -> Either ParserException U.Value+parseExpandValue = fmap expandValue . parseValue+ -- Primitive instruction ------------------ @@ -114,8 +127,11 @@ -- -- This function is part of the module API, its semantics should not change. codeEntry :: Parser [ParsedOp]-codeEntry = ops+codeEntry = bracewrappedOps +bracewrappedOps :: Parser [ParsedOp]+bracewrappedOps = lookAhead (symbol "{") *> ops+ parsedOp :: Parser ParsedOp parsedOp = do   lms <- asks letMacros@@ -126,7 +142,7 @@     , flip Prim pos <$> prim     , flip Mac pos <$> macro parsedOp     , primOrMac-    , flip Seq pos <$> ops+    , flip Seq pos <$> bracewrappedOps     ]   where     lmacWithPos :: Parser LetMacro -> Parser ParsedOp
src/Michelson/Parser/Error.hs view
@@ -10,23 +10,36 @@   ) where  import Data.Data (Data(..))-import Fmt (Buildable(build))+import Fmt (Buildable(build), (+|), (|+)) import Text.Megaparsec (ParseErrorBundle, ShowErrorComponent(..), errorBundlePretty) import qualified Text.Show (show) +import Util.Instances ()+import Util.Named ()+import Util.Positive+ data CustomParserException   = UnknownTypeException   | StringLiteralException StringLiteralParserException   | OddNumberBytesException-  | ProhibitedLetType Text+  | WrongTagArgs Natural Positive+  | WrongAccessArgs Natural Positive+  | WrongSetArgs Natural Positive   deriving stock (Eq, Data, Ord, Show)  instance ShowErrorComponent CustomParserException where   showErrorComponent UnknownTypeException = "unknown type"   showErrorComponent (StringLiteralException e) = showErrorComponent e   showErrorComponent OddNumberBytesException = "odd number bytes"-  showErrorComponent (ProhibitedLetType t) =-    "prohibited name for type alias in let macros: " <> toString t+  showErrorComponent (WrongTagArgs idx size) =+    "TAG: too large index: " +| idx |+ " \+           \exceedes union size " +| size |+ ""+  showErrorComponent (WrongAccessArgs idx size) =+    "ACCESS: too large index: " +| idx |+ " \+           \exceedes tuple size " +| size |+ ""+  showErrorComponent (WrongSetArgs idx size) =+    "SET: too large index: " +| idx |+ " \+           \exceedes tuple size " +| size |+ ""  data StringLiteralParserException   = InvalidEscapeSequence Char
src/Michelson/Parser/Ext.hs view
@@ -10,12 +10,11 @@  import Prelude hiding (try) - import Text.Megaparsec (choice, satisfy, try) import Text.Megaparsec.Char (alphaNumChar, string) import qualified Text.Megaparsec.Char.Lexer as L -import Michelson.Macro (ParsedOp(..), ParsedUExtInstr, ParsedUTestAssert)+import Michelson.Macro (ParsedOp(..), ParsedUExtInstr) import Michelson.Parser.Lexer import Michelson.Parser.Type import Michelson.Parser.Types (Parser)@@ -34,7 +33,7 @@ printOp :: Parser ParsedUExtInstr printOp = symbol' "PRINT" >> U.UPRINT <$> printComment -testAssert :: Parser [ParsedOp] -> Parser ParsedUTestAssert+testAssert :: Parser [ParsedOp] -> Parser (U.TestAssert ParsedOp) testAssert opsParser = do   n <- lexeme (toText <$> some alphaNumChar)   c <- printComment
src/Michelson/Parser/Helpers.hs view
@@ -3,14 +3,18 @@   , sepEndBy1   , sepBy2   , parseDef+  , positive+  , mparens   ) where  import Data.Default (Default(..)) import qualified Data.List.NonEmpty as NE import qualified Text.Megaparsec as P+import Text.Megaparsec.Char.Lexer (decimal) -import Michelson.Parser.Lexer (symbol')+import Michelson.Parser.Lexer (parens, symbol') import Michelson.Parser.Types (Parser)+import Util.Positive  sepEndBy1 :: MonadPlus m => m a -> m sep -> m (NonEmpty a) sepEndBy1 = fmap NE.fromList ... P.sepEndBy1@@ -30,3 +34,14 @@ -- | Apply given parser and return default value if it fails. parseDef :: Default a => Parser a -> Parser a parseDef a = P.try a <|> pure def++-- | Parse a positive number.+positive :: Parser Positive+positive = do+  n :: Integer <- decimal+  mkPositive n+    & either (fail . toString) pure++-- | Parse expression which can be wrapped in parentheses.+mparens :: Parser a -> Parser a+mparens p = p <|> parens p
src/Michelson/Parser/Instr.hs view
@@ -11,7 +11,8 @@  import Prelude hiding (EQ, GT, LT, many, note, some, try) -import Text.Megaparsec (choice, sepEndBy, try)+import Text.Megaparsec (choice, notFollowedBy, sepEndBy, try)+import qualified Text.Megaparsec.Char.Lexer as L  import Michelson.Let (LetValue(..)) import Michelson.Macro (ParsedInstr, ParsedOp(..))@@ -25,23 +26,23 @@ -- | Parser for primitive Michelson instruction (no macros and extensions). primInstr :: Parser (Contract' ParsedOp) -> Parser ParsedOp -> Parser ParsedInstr primInstr contractParser opParser = choice-  [ dropOp, dupOp, swapOp, pushOp opParser, someOp, noneOp, unitOp+  [ dropOp, dupOp, swapOp, digOp, dugOp, pushOp opParser, someOp, noneOp, unitOp   , ifNoneOp opParser, carOp, cdrOp, leftOp, rightOp, ifLeftOp opParser, nilOp-  , consOp, ifConsOp opParser, sizeOp, emptySetOp, emptyMapOp, iterOp opParser+  , consOp, ifConsOp opParser, sizeOp, emptySetOp, emptyMapOp, emptyBigMapOp, iterOp opParser   , memOp, getOp, updateOp, loopLOp opParser, loopOp opParser-  , lambdaOp opParser, execOp, dipOp opParser, failWithOp, castOp, renameOp+  , lambdaOp opParser, execOp, applyOp, dipOp opParser, failWithOp, castOp, renameOp   , concatOp, packOp, unpackOp, sliceOp, isNatOp, addressOp, addOp, subOp   , mulOp, edivOp, absOp, negOp, lslOp, lsrOp, orOp, andOp, xorOp, notOp   , compareOp, eqOp, neqOp, ltOp, leOp, gtOp, geOp, intOp, selfOp, contractOp-  , transferTokensOp, setDelegateOp, createAccountOp+  , transferTokensOp, setDelegateOp   , createContractOp contractParser, implicitAccountOp, nowOp, amountOp   , balanceOp, checkSigOp, sha256Op, sha512Op, blake2BOp, hashKeyOp-  , stepsToQuotaOp, sourceOp, senderOp+  , stepsToQuotaOp, sourceOp, senderOp, chainIdOp   ]  -- | Parse a sequence of instructions. ops' :: Parser ParsedOp -> Parser [ParsedOp]-ops' opParser = braces $ sepEndBy opParser semicolon+ops' opParser = (braces $ sepEndBy opParser semicolon) <|> (pure <$> opParser)  -- Control Structures @@ -57,13 +58,24 @@ execOp :: Parser ParsedInstr execOp = do void $ symbol' "EXEC"; EXEC <$> noteVDef +applyOp :: Parser ParsedInstr+applyOp = do void $ symbol' "APPLY"; APPLY <$> noteVDef++-- Parses both `DIP` and `DIP n`. dipOp :: Parser ParsedOp -> Parser ParsedInstr-dipOp opParser = do void $ symbol' "DIP"; DIP <$> ops' opParser+dipOp opParser = parseWithOptionalParameter "DIP" DIPN DIP <*> ops' opParser +-- Helper for instructions which have optional numeric non-negative parameter.+parseWithOptionalParameter :: Text -> (Word -> instr) -> instr -> Parser instr+parseWithOptionalParameter instrName constructorWithParam constructorNoParam =+  symbol' instrName *>+  (try (constructorWithParam <$> lexeme L.decimal) <|> pure constructorNoParam)+ -- Stack Operations +-- Parses both `DROP` and `DROP n`. dropOp :: Parser ParsedInstr-dropOp = do symbol' "DROP"; return DROP;+dropOp = parseWithOptionalParameter "DROP" DROPN DROP  dupOp :: Parser ParsedInstr dupOp = do void $ symbol' "DUP"; DUP <$> noteVDef@@ -71,6 +83,12 @@ swapOp :: Parser ParsedInstr swapOp = do symbol' "SWAP"; return SWAP; +digOp :: Parser ParsedInstr+digOp = symbol' "DIG" *> (DIG <$> lexeme L.decimal)++dugOp :: Parser ParsedInstr+dugOp = symbol' "DUG" *> (DUG <$> lexeme L.decimal)+ pushOp :: Parser ParsedOp -> Parser ParsedInstr pushOp opParser = do   symbol' "PUSH"@@ -151,7 +169,7 @@ absOp = do void $ symbol' "ABS"; ABS <$> noteVDef  negOp :: Parser ParsedInstr-negOp = do symbol' "NEG"; return NEG;+negOp = do void $ symbol' "NEG"; NEG <$> noteVDef  -- Bitwise logical operators @@ -189,11 +207,15 @@ emptyMapOp = do symbol' "EMPTY_MAP"; (t, v) <- notesTV; a <- comparable;                 EMPTY_MAP t v a <$> type_ +emptyBigMapOp :: Parser ParsedInstr+emptyBigMapOp = do symbol' "EMPTY_BIG_MAP"; (t, v) <- notesTV; a <- comparable;+                   EMPTY_BIG_MAP t v a <$> type_+ memOp :: Parser ParsedInstr memOp = do void $ symbol' "MEM"; MEM <$> noteVDef  updateOp :: Parser ParsedInstr-updateOp = do symbol' "UPDATE"; return UPDATE+updateOp = do void $ symbol' "UPDATE"; UPDATE <$> noteVDef  iterOp :: Parser ParsedOp -> Parser ParsedInstr iterOp opParser = do void $ symbol' "ITER"; ITER <$> ops' opParser@@ -211,7 +233,11 @@ nilOp = do symbol' "NIL"; (t, v) <- notesTV; NIL t v <$> type_  consOp :: Parser ParsedInstr-consOp = do void $ symbol' "CONS"; CONS <$> noteVDef+consOp = do+  try . lexeme $ do+    void $ string' "CONS"+    notFollowedBy (string' "T")+  CONS <$> noteVDef  ifConsOp :: Parser ParsedOp -> Parser ParsedInstr ifConsOp opParser =@@ -221,10 +247,10 @@ -- Operations on options  someOp :: Parser ParsedInstr-someOp = do symbol' "SOME"; (t, v, f) <- notesTVF; return $ SOME t v f+someOp = do symbol' "SOME"; (t, v) <- notesTV; return $ SOME t v  noneOp :: Parser ParsedInstr-noneOp = do symbol' "NONE"; (t, v, f) <- notesTVF; NONE t v f <$> type_+noneOp = do symbol' "NONE"; (t, v) <- notesTV; NONE t v <$> type_  ifNoneOp :: Parser ParsedOp -> Parser ParsedInstr ifNoneOp opParser =@@ -254,10 +280,6 @@   symbol' "CREATE_CONTRACT" *>   (CREATE_CONTRACT <$> noteVDef <*> noteVDef <*> braces contractParser) -createAccountOp :: Parser ParsedInstr-createAccountOp = do symbol' "CREATE_ACCOUNT"; v <- noteVDef; v' <- noteVDef;-                       return $ CREATE_ACCOUNT v v'- transferTokensOp :: Parser ParsedInstr transferTokensOp = do void $ symbol' "TRANSFER_TOKENS"; TRANSFER_TOKENS <$> noteVDef @@ -268,7 +290,7 @@ balanceOp = do void $ symbol' "BALANCE"; BALANCE <$> noteVDef  contractOp :: Parser ParsedInstr-contractOp = do void $ symbol' "CONTRACT"; CONTRACT <$> noteVDef <*> type_+contractOp = do void $ symbol' "CONTRACT"; CONTRACT <$> noteVDef <*> noteFDef <*> type_  sourceOp :: Parser ParsedInstr sourceOp = do void $ symbol' "SOURCE"; SOURCE <$> noteVDef@@ -295,6 +317,9 @@  stepsToQuotaOp :: Parser ParsedInstr stepsToQuotaOp = do void $ symbol' "STEPS_TO_QUOTA"; STEPS_TO_QUOTA <$> noteVDef++chainIdOp :: Parser ParsedInstr+chainIdOp = do void $ symbol' "CHAIN_ID"; CHAIN_ID <$> noteVDef  -- Operations on bytes 
src/Michelson/Parser/Let.hs view
@@ -13,12 +13,11 @@ import qualified Data.Map as Map import qualified Data.Set as Set -import Text.Megaparsec (choice, customFailure, satisfy, try)+import Text.Megaparsec (choice, satisfy, try) import Text.Megaparsec.Char (lowerChar, upperChar) -import Michelson.Let (LetValue(..), LetType(..))-import Michelson.Macro (ParsedOp(..), LetMacro(..))-import Michelson.Parser.Error+import Michelson.Let (LetType(..), LetValue(..))+import Michelson.Macro (LetMacro(..), ParsedOp(..)) import Michelson.Parser.Ext import Michelson.Parser.Helpers import Michelson.Parser.Instr@@ -84,15 +83,11 @@ letType = lexeme $ do   symbol "type"   n <- letName upperChar <|> letName lowerChar-  when (n == "Parameter" || n == "Storage") (customFailure $ ProhibitedLetType n)   symbol "="-  t <- type_-  case t of-    (Type t' a) ->-      if a == noAnn-      then return $ LetType n (Type t' (ann n))-      else return $ LetType n t-    _ -> return $ LetType n t+  t@(Type t' a) <- type_+  return $ if a == noAnn+    then LetType n (Type t' (ann n))+    else LetType n t  letValue :: Parser ParsedOp -> Parser LetValue letValue opParser = lexeme $ do
src/Michelson/Parser/Macro.hs view
@@ -10,24 +10,29 @@  import Prelude hiding (try) -import Fmt ((+|), (+||), (|+), (||+))-import Text.Megaparsec (notFollowedBy, try)+import Text.Megaparsec (customFailure, notFollowedBy, try) import Text.Megaparsec.Char.Lexer (decimal)  import Michelson.Macro (CadrStruct(..), Macro(..), PairStruct(..), ParsedOp(..)) import qualified Michelson.Macro as Macro import Michelson.Parser.Annotations+import Michelson.Parser.Error+import Michelson.Parser.Helpers import Michelson.Parser.Instr import Michelson.Parser.Lexer import Michelson.Parser.Type import Michelson.Parser.Types (Parser) import Michelson.Untyped (T(..), Type(..), noAnn) import Util.Alternative (someNE)+import Util.Positive  macro :: Parser ParsedOp -> Parser Macro macro opParser =       do symbol' "CASE"; is <- someNE ops; return $ CASE is   <|> do symbol' "TAG"; tagMac+  <|> do symbol' "ACCESS"; accessMac+  <|> do symbol' "SET "; setMac+  <|> do symbol' "CONSTRUCT"; is <- someNE ops; return $ CONSTRUCT is   <|> do symbol' "VIEW"; a <- ops; return $ VIEW a   <|> do symbol' "VOID"; a <- ops; return $ VOID a   <|> do symbol' "CMP"; a <- cmpOp; CMP a <$> noteVDef@@ -113,12 +118,29 @@   mSpace   ty <- type_   let utys = unrollUnion ty []-  when (idx >= fromIntegral (length utys)) $-    fail $ "TAG: too large index: " +|| idx ||+ " \-           \exceedes size of union " +| toList utys |+ ""+  when (fromIntegral idx >= length utys) $+    customFailure $ WrongTagArgs idx (lengthNE utys)   return $ TAG idx utys   where   unrollUnion ty =     case ty of       Type (TOr _ _ l r) _ -> unrollUnion l . toList . unrollUnion r       _ -> (ty :|)++accessMac :: Parser Macro+accessMac = do+  idx <- decimal+  mSpace+  size <- positive+  when (idx >= unPositive size) $+    customFailure $ WrongAccessArgs idx size+  return $ ACCESS idx size++setMac :: Parser Macro+setMac = do+  idx <- decimal+  mSpace+  size <- positive+  when (idx >= unPositive size) $+    customFailure $ WrongSetArgs idx size+  return $ SET idx size
src/Michelson/Parser/Type.hs view
@@ -2,7 +2,6 @@  module Michelson.Parser.Type   ( type_-  , explicitType   , comparable   ) where @@ -23,42 +22,26 @@  -- | Parse untyped Michelson 'Type` (i. e. one with annotations). type_ :: Parser Type-type_ = typeHelper implicitTypes---- | Parse only explicit `Type`, `Parameter` and `Storage` are prohibited-explicitType :: Parser Type-explicitType = typeHelper empty--typeHelper :: Parser Type -> Parser Type-typeHelper implicitParser = ti <|> parens ti <|> customFailure UnknownTypeException+type_ = mparens ti <|> customFailure UnknownTypeException   where-    ti = snd <$> (lexeme $ typeInner implicitParser (pure noAnn)) <|> implicitParser+    ti = snd <$> (lexeme $ typeInner (pure noAnn))  typeInner-  :: Parser Type-  -> Parser FieldAnn -> Parser (FieldAnn, Type)-typeInner implicit fp = choice $ (\x -> x fp) <$>-  [ t_ct, t_key, t_unit, t_signature, t_option implicit, t_list implicit, t_set-  , t_operation, t_contract implicit, t_pair implicit, t_or implicit-  , t_lambda implicit, t_map implicit, t_big_map implicit, t_view implicit-  , t_void implicit, t_letType+  :: Parser FieldAnn -> Parser (FieldAnn, Type)+typeInner fp = choice $ (\x -> x fp) <$>+  [ t_ct, t_key, t_unit, t_signature, t_chain_id+  , t_option, t_list, t_set+  , t_operation, t_contract, t_pair, t_or+  , t_lambda, t_map, t_big_map, t_view+  , t_void, t_letType   ] -implicitTypes :: Parser Type-implicitTypes = choice [t_parameter, t_storage]- ---------------------------------------------------------------------------- -- Comparable types ----------------------------------------------------------------------------  comparable :: Parser Comparable-comparable = let c = do ct' <- ct; Comparable ct' <$> noteTDef in parens c <|> c--t_parameter :: Parser Type-t_parameter = do void $ symbol' "Parameter"; return TypeParameter--t_storage :: Parser Type-t_storage = do void $ symbol' "Storage"; return TypeStorage+comparable = let c = do ct' <- ct; Comparable ct' <$> noteTDef in mparens c  t_ct :: (Default a) => Parser a -> Parser (a, Type) t_ct fp = do ct' <- ct; (f,t) <- fieldType fp; return (f, Type (Tc ct') t)@@ -78,10 +61,10 @@ -- Non-comparable types ---------------------------------------------------------------------------- -field :: Parser Type -> Parser (FieldAnn, Type)-field implicit = lexeme (fi <|> parens fi)+field :: Parser (FieldAnn, Type)+field = lexeme (mparens fi)   where-    fi = typeInner implicit noteF+    fi = typeInner noteF  t_key :: (Default a) => Parser a -> Parser (a, Type) t_key fp = do symbol' "Key"; (f,t) <- fieldType fp; return (f, Type TKey t)@@ -89,14 +72,20 @@ t_signature :: (Default a) => Parser a -> Parser (a, Type) t_signature fp = do symbol' "Signature"; (f, t) <- fieldType fp; return (f, Type TSignature t) +t_chain_id :: (Default a) => Parser a -> Parser (a, Type)+t_chain_id fp = do+  symbol' "ChainId" <|> symbol' "chain_id"+  (f, t) <- fieldType fp+  return (f, Type TChainId t)+ t_operation :: (Default a) => Parser a -> Parser (a, Type) t_operation fp = do symbol' "Operation"; (f, t) <- fieldType fp; return (f, Type TOperation t) -t_contract :: (Default a) => Parser Type -> Parser a -> Parser (a, Type)-t_contract implicit fp = do+t_contract :: (Default a) => Parser a -> Parser (a, Type)+t_contract fp = do   symbol' "Contract"   (f, t) <- fieldType fp-  a <- typeHelper implicit+  a <- type_   return (f, Type (TContract a) t)  t_unit :: (Default a) => Parser a -> Parser (a, Type)@@ -108,93 +97,79 @@ t_pair_like   :: (Default a)   => (FieldAnn -> FieldAnn -> Type -> Type -> T)-  -> Parser Type   -> Parser a   -> Parser (a, Type)-t_pair_like mkPair implicit fp = do+t_pair_like mkPair fp = do   (f, t) <- fieldType fp-  (l, a) <- implicitF-  (r, b) <- implicitF+  (l, a) <- field+  (r, b) <- field   return (f, Type (mkPair l r a b) t)-  where-    implicitF = field implicit <|> (,) <$> noteFDef <*> implicit -t_pair :: (Default a) => Parser Type -> Parser a -> Parser (a, Type)-t_pair implicit fp = core <|> tuple+t_pair :: (Default a) => Parser a -> Parser (a, Type)+t_pair fp = core <|> tuple   where     core = do       symbol' "Pair"-      t_pair_like TPair implicit fp+      t_pair_like TPair fp     tuple = try $ do-      symbol "("-      (l, r, a, b) <- typePair-      symbol ")"+      (_, Type ty _) <- parens tupleInner       (f, t) <- fieldType fp-      return (f, Type (TPair l r a b) t)-    tupleInner = try $ do-      (l, r, a, b) <- typePair-      return (noAnn, Type (TPair l r a b) noAnn)-    implicitF = field implicit <|> (,) <$> noteFDef <*> implicit-    typePair = do-      (l, a) <- implicitF-      comma-      (r, b) <- tupleInner <|> implicitF-      return (l, r, a, b)+      return (f, Type ty t)+    tupleInner = do+      fs <- sepBy2 field comma+      let mergeTwo _ (l, a) (r, b) = (noAnn, Type (TPair l r a b) noAnn)+      return $ mkGenericTree mergeTwo fs -t_or :: (Default a) => Parser Type -> Parser a -> Parser (a, Type)-t_or implicit fp = core <|> bar+t_or :: (Default a) => Parser a -> Parser (a, Type)+t_or fp = core <|> bar   where     core = do       symbol' "Or"-      t_pair_like TOr implicit fp+      t_pair_like TOr fp     bar = try $ do-      symbol "("-      (_, Type ty _) <- barInner-      symbol ")"+      (_, Type ty _) <- parens barInner       (f, t) <- fieldType fp       return (f, Type ty t)     barInner = do-      fs <- sepBy2 implicitF (symbol "|")+      fs <- sepBy2 field (symbol "|")       let mergeTwo _ (l, a) (r, b) = (noAnn, Type (TOr l r a b) noAnn)       return $ mkGenericTree mergeTwo fs-    implicitF = field implicit <|> (,) <$> noteFDef <*> implicit -t_option :: (Default a) => Parser Type -> Parser a -> Parser (a, Type)-t_option implicit fp = do+t_option :: (Default a) => Parser a -> Parser (a, Type)+t_option fp = do   symbol' "Option"   (f, t) <- fieldType fp-  (fa, a) <- field implicit <|> (,) <$> noteFDef <*> implicit-  return (f, Type (TOption fa a) t)+  a <- mparens $ snd <$> typeInner (pure noAnn)+  return (f, Type (TOption a) t) -t_lambda :: (Default a) => Parser Type -> Parser a -> Parser (a, Type)-t_lambda implicit fp = core <|> slashLambda+t_lambda :: (Default a) => Parser a -> Parser (a, Type)+t_lambda fp = core <|> slashLambda   where     core = do       symbol' "Lambda"       (f, t) <- fieldType fp-      a <- implicitType-      b <- implicitType+      a <- type_+      b <- type_       return (f, Type (TLambda a b) t)     slashLambda = do       symbol "\\"       (f, t) <- fieldType fp-      a <- implicitType+      a <- type_       symbol "->"-      b <- implicitType+      b <- type_       return (f, Type (TLambda a b) t)-    implicitType = typeHelper implicit  -- Container types-t_list :: (Default a) => Parser Type -> Parser a -> Parser (a, Type)-t_list implicit fp = core <|> bracketList+t_list :: (Default a) => Parser a -> Parser (a, Type)+t_list fp = core <|> bracketList   where     core = do       symbol' "List"       (f, t) <- fieldType fp-      a <- typeHelper implicit+      a <- type_       return (f, Type (TList a) t)     bracketList = do-      a <- brackets (typeHelper implicit)+      a <- brackets type_       (f, t) <- fieldType fp       return (f, Type (TList a) t) @@ -213,45 +188,43 @@  t_map_like   :: Default a-  => Parser Type -> Parser a -> Parser (Comparable, Type, a, TypeAnn)-t_map_like implicit fp = do+  => Parser a -> Parser (Comparable, Type, a, TypeAnn)+t_map_like fp = do   (f, t) <- fieldType fp   a <- comparable-  b <- typeHelper implicit+  b <- type_   return (a, b, f, t) -t_map :: (Default a) => Parser Type -> Parser a -> Parser (a, Type)-t_map implicit fp = do+t_map :: (Default a) => Parser a -> Parser (a, Type)+t_map fp = do   symbol' "Map"-  (a, b, f, t) <- t_map_like implicit fp+  (a, b, f, t) <- t_map_like fp   return (f, Type (TMap a b) t) -t_big_map :: (Default a) => Parser Type -> Parser a -> Parser (a, Type)-t_big_map implicit fp = do+t_big_map :: (Default a) => Parser a -> Parser (a, Type)+t_big_map fp = do   symbol' "BigMap" <|> symbol "big_map"-  (a, b, f, t) <- t_map_like implicit fp+  (a, b, f, t) <- t_map_like fp   return (f, Type (TBigMap a b) t)  ---------------------------------------------------------------------------- -- Non-standard types (Morley extensions) ---------------------------------------------------------------------------- -t_view :: Default a => Parser Type -> Parser a -> Parser (a, Type)-t_view implicit fp = do+t_view :: Default a => Parser a -> Parser (a, Type)+t_view fp = do   symbol' "View"-  a <- typeHelper implicit-  r <- typeHelper implicit+  a <- type_+  r <- type_   (f, t) <- fieldType fp-  let r' = Type (TOption noAnn r) noAnn-  let c = Type (TPair noAnn noAnn a r') noAnn-  let c' = Type (TContract c) noAnn+  let c' = Type (TContract r) noAnn   return (f, Type (TPair noAnn noAnn a c') t) -t_void :: Default a => Parser Type -> Parser a -> Parser (a, Type)-t_void implicit fp = do+t_void :: Default a => Parser a -> Parser (a, Type)+t_void fp = do   symbol' "Void"-  a <- typeHelper implicit-  b <- typeHelper implicit+  a <- type_+  b <- type_   (f, t) <- fieldType fp   let c = Type (TLambda b b) noAnn   return (f, Type (TPair noAnn noAnn a c) t)
src/Michelson/Parser/Value.hs view
@@ -32,7 +32,7 @@ -- | Parse untyped 'ParsedValue'. Take instruction parser as argument -- to avoid cyclic dependencies between modules, hence ' in its name. value' :: Parser ParsedOp -> Parser ParsedValue-value' opParser = lexeme $ valueInner' <|> parens valueInner'+value' opParser = lexeme $ mparens valueInner'   where     valueInner' = valueInner opParser @@ -41,8 +41,11 @@   [ stringLiteral, bytesLiteral, intLiteral, unitValue   , trueValue, falseValue, pairValue opParser, leftValue opParser   , rightValue opParser, someValue opParser, noneValue, nilValue-  , seqValue opParser, mapValue opParser, lambdaValue opParser, dataLetValue+  , seqOrLambda opParser, mapValue opParser, dataLetValue   ]++seqOrLambda :: Parser ParsedOp -> Parser ParsedValue+seqOrLambda opParser = try (lambdaValue opParser) <|> seqValue opParser  stringLiteral :: Parser ParsedValue stringLiteral = U.ValueString . mkMTextUnsafe . toText <$> do
+ src/Michelson/Preprocess.hs view
@@ -0,0 +1,77 @@+-- | Apply some transformations to Michelson code.++module Michelson.Preprocess+  ( transformStrings+  , transformBytes+  ) where++import Data.Default (def)+import qualified Data.Map.Strict as Map+import qualified Data.Set as Set++import Michelson.Text (MText)+import Michelson.Typed++-- Note: we may add such transformation for long bytestrings as well if deemed necessary.+-- And for other constants which may be arbitrarily large (e. g. lists).+-- For now we need it only for strings and probably won't need for anything else.++-- | Transform all strings in a typed instructions using given+-- function. The first argument specifies whether we should go into+-- arguments that contain instructions.+transformStrings :: Bool -> (MText -> MText) -> Instr inp out -> Instr inp out+transformStrings goToValues f = transformConstants goToValues valF+  where+    cvalF :: CValue t -> CValue t+    cvalF = \case+      CvString str -> CvString $ f str+      cv -> cv++    valF :: Value t -> Value t+    valF = \case+      VC cval -> VC (cvalF cval)+      VOption mv -> VOption (valF <$> mv)+      VList vs -> VList (valF <$> vs)+      VSet vSet -> VSet (Set.map cvalF vSet)+      VPair (v1, v2) -> VPair (valF v1, valF v2)+      VOr eith -> VOr (bimap valF valF eith)+      VMap m -> VMap . fmap valF . Map.mapKeys cvalF $ m+      VBigMap m -> VBigMap . fmap valF . Map.mapKeys cvalF $ m+      -- We do not handle 'VLam' here, because 'dfsInstr' takes care of that.+      v -> v++-- | Similar to 'transformStrings' but for bytes.+-- TODO [TM-375]: deduplicate+transformBytes :: Bool -> (ByteString -> ByteString) -> Instr inp out -> Instr inp out+transformBytes goToValues f = transformConstants goToValues valF+  where+    cvalF :: CValue t -> CValue t+    cvalF = \case+      CvBytes str -> CvBytes $ f str+      cv -> cv++    valF :: Value t -> Value t+    valF = \case+      VC cval -> VC (cvalF cval)+      VOption mv -> VOption (valF <$> mv)+      VList vs -> VList (valF <$> vs)+      VSet vSet -> VSet (Set.map cvalF vSet)+      VPair (v1, v2) -> VPair (valF v1, valF v2)+      VOr eith -> VOr (bimap valF valF eith)+      VMap m -> VMap . fmap valF . Map.mapKeys cvalF $ m+      VBigMap m -> VBigMap . fmap valF . Map.mapKeys cvalF $ m+      -- We do not handle 'VLam' here, because 'dfsInstr' takes care of that.+      v -> v++transformConstants ::+     forall inp out.+     Bool+  -> (forall t. Value t -> Value t)+  -> Instr inp out+  -> Instr inp out+transformConstants dsGoToValues f = fst . dfsInstr def{ dsGoToValues } step+  where+    step :: forall i o. Instr i o -> (Instr i o, ())+    step = (,()) . \case+      PUSH v -> PUSH (f v)+      i -> i
src/Michelson/Printer.hs view
@@ -3,21 +3,43 @@   , printDoc   , printUntypedContract   , printTypedContract+  , printTypedFullContract+  , printSomeContract+  , printTypedValue   ) where +import Data.Constraint (withDict) import Data.Singletons (SingI) import qualified Data.Text.Lazy as TL -import Michelson.Printer.Util (RenderDoc(..), printDoc)+import Michelson.Printer.Util (RenderDoc(..), doesntNeedParens, printDoc)+import Michelson.TypeCheck.Types (SomeContract(..)) import qualified Michelson.Typed as T import qualified Michelson.Untyped as U  -- | Convert an untyped contract into a textual representation which -- will be accepted by the OCaml reference client.-printUntypedContract :: (RenderDoc op) => U.Contract' op -> TL.Text-printUntypedContract = printDoc . renderDoc+printUntypedContract :: (RenderDoc op) => Bool -> U.Contract' op -> TL.Text+printUntypedContract forceSingleLine = printDoc forceSingleLine . renderDoc doesntNeedParens  -- | Convert a typed contract into a textual representation which -- will be accepted by the OCaml reference client.-printTypedContract :: (SingI p, SingI s) => T.Contract p s -> TL.Text-printTypedContract = printUntypedContract . T.convertContract+printTypedContract :: (SingI p, SingI s) => Bool -> T.Contract p s -> TL.Text+printTypedContract forceSingleLine =+  printUntypedContract forceSingleLine . T.convertContract++printTypedFullContract :: Bool -> T.FullContract p s -> TL.Text+printTypedFullContract forceSingleLine fc@T.FullContract{} =+  printUntypedContract forceSingleLine $ T.convertFullContract fc++printTypedValue+  :: forall t.+      (T.ProperPrintedValBetterErrors t)+  => Bool -> T.Value t -> TL.Text+printTypedValue forceSingleLine =+  withDict (T.properPrintedValEvi @t) $+  printDoc forceSingleLine . renderDoc doesntNeedParens . T.untypeValue++printSomeContract :: Bool -> SomeContract -> TL.Text+printSomeContract forceSingleLine (SomeContract fc) =+  printTypedFullContract forceSingleLine fc
src/Michelson/Printer/Util.hs view
@@ -1,24 +1,43 @@ module Michelson.Printer.Util   ( RenderDoc(..)+  , Prettier(..)   , printDoc   , renderOps   , renderOpsList   , spaces   , wrapInParens   , buildRenderDoc++    -- * Smart parentheses+  , RenderContext+  , needsParens+  , doesntNeedParens+  , addParens+  , assertParensNotNeeded   ) where +import Control.Exception (assert) import qualified Data.Text.Lazy as LT import Data.Text.Lazy.Builder (Builder) import Text.PrettyPrint.Leijen.Text-  (Doc, SimpleDoc, braces, displayB, displayT, hcat, isEmpty, parens, punctuate, renderOneLine,-  semi, space, vcat, (<+>))+  (Doc, SimpleDoc, align, braces, displayB, displayT, enclose, hcat, isEmpty, parens, punctuate,+  renderOneLine, renderPretty, semi, space, vcat, (<+>)) +-- | Environment carried during recursive rendering.+newtype RenderContext = RenderContext+  { _rcWillNeedParens :: Bool+    -- ^ Whether the current expression is going to be used as part of+    -- top-level expression or in a similar context.+    -- When set to 'True', you may need to wrap your rendered expression into+    -- parentheses.+  }+ -- | Generalize converting a type into a -- Text.PrettyPrint.Leijen.Text.Doc. Used to pretty print Michelson code -- and define Fmt.Buildable instances. class RenderDoc a where-  renderDoc :: a -> Doc+  renderDoc :: RenderContext -> a -> Doc+   -- | Whether a value can be represented in Michelson code.   -- Normally either all values of some type are renderable or not renderable.   -- However, in case of instructions we have extra instructions which should@@ -29,9 +48,14 @@   isRenderable :: a -> Bool   isRenderable _ = True +-- | A new type that can wrap values so that the RenderDoc+-- instances of the combined value can have a different+-- behavior for the pretty printer.+newtype Prettier a = Prettier a+ -- | Convert 'Doc' to 'Text' with a line width of 80.-printDoc :: Doc -> LT.Text-printDoc = displayT . doRender+printDoc :: Bool -> Doc -> LT.Text+printDoc oneLine = displayT . doRender oneLine  -- | Generic way to render the different op types that get passed -- to a contract.@@ -43,25 +67,56 @@  renderOpsList :: (RenderDoc op) => Bool -> [op] -> Doc renderOpsList oneLine ops =-  braces $ cat' $ punctuate semi (renderDoc <$> filter isRenderable ops)+  braces $+    enclose space space $+      cat' $ punctuate semi $+        renderDoc doesntNeedParens <$> filter isRenderable ops   where-    cat' = if oneLine then maybe "" spacecat . nonEmpty else vcat+    cat' = if oneLine then maybe "" spacecat . nonEmpty else align . vcat  -- | Create a specific number of spaces. spaces :: Int -> Doc spaces x = hcat $ replicate x space  -- | Wrap documents in parentheses if there are two or more in the list.-wrapInParens :: NonEmpty Doc -> Doc-wrapInParens ds =-  if (length $ filter (not . isEmpty) (toList ds)) > 1-    then parens $ foldr (<+>) mempty ds-    else foldr (<+>) mempty ds+wrapInParens :: RenderContext -> NonEmpty Doc -> Doc+wrapInParens (RenderContext pn) ds =+  let moreThanOne = length (filter (not . isEmpty) (toList ds)) > 1+  in  addParens (RenderContext (pn && moreThanOne)) $+        foldr (<+>) mempty ds  -- | Turn something that is instance of `RenderDoc` into a `Builder`. -- It's formatted the same way as `printDoc` formats docs. buildRenderDoc :: RenderDoc a => a -> Builder-buildRenderDoc = displayB . doRender . renderDoc+buildRenderDoc = displayB . doRender True . renderDoc doesntNeedParens -doRender :: Doc -> SimpleDoc-doRender = renderOneLine+-- | Here using a page width of 80 and a ribbon width of 1.0+-- https://hackage.haskell.org/package/wl-pprint-1.2.1/docs/Text-PrettyPrint-Leijen.html+doRender :: Bool -> Doc -> SimpleDoc+doRender oneLine = if oneLine then renderOneLine else renderPretty 1.0 80++-- Smart parentheses+----------------------------------------------------------------------------++{- Motivation:++Some expressions may need to be wrapped into parentheses, but only if they+are part of other expression, and are not already wrapped into braces or+brackets.+-}++-- | 'ParensNeeded' constant.+needsParens, doesntNeedParens :: RenderContext+needsParens = RenderContext True+doesntNeedParens = RenderContext False++-- | Add parentheses if needed.+addParens :: RenderContext -> Doc -> Doc+addParens = \case+  RenderContext True -> parens+  RenderContext False -> id++-- | Ensure parentheses are not required, for case when you cannot+-- sensibly wrap your expression into them.+assertParensNotNeeded :: HasCallStack => RenderContext -> a -> a+assertParensNotNeeded (RenderContext pn) = assert (not pn)
src/Michelson/Runtime.hs view
@@ -1,35 +1,35 @@ -- | Interpreter and typechecker of a contract in Morley language.  module Michelson.Runtime-       (-         -- * High level interface for end user-         originateContract-       , runContract-       , transfer+  (+    -- * High level interface for end user+    originateContract+  , runContract+  , transfer -       -- * Other helpers-       , parseContract-       , parseExpandContract-       , readAndParseContract-       , prepareContract-       , typeCheckWithDb+  -- * Other helpers+  , parseContract+  , parseExpandContract+  , readAndParseContract+  , prepareContract+  , typeCheckWithDb -       -- * Re-exports-       , ContractState (..)-       , AddressState (..)-       , TxData (..)+  -- * Re-exports+  , ContractState (..)+  , AddressState (..)+  , TxData (..) -       -- * For testing-       , InterpreterOp (..)-       , InterpreterRes (..)-       , InterpreterError' (..)-       , InterpreterError-       , interpreterPure+  -- * For testing+  , InterpreterOp (..)+  , InterpreterRes (..)+  , InterpreterError' (..)+  , InterpreterError+  , interpreterPure -       -- * To avoid warnings (can't generate lenses only for some fields)-       , irInterpretResults-       , irUpdates-       ) where+  -- * To avoid warnings (can't generate lenses only for some fields)+  , irInterpretResults+  , irUpdates+  ) where  import Control.Lens (at, makeLenses, (%=)) import Control.Monad.Except (Except, runExcept, throwError)@@ -39,20 +39,22 @@ import Text.Megaparsec (parse)  import Michelson.Interpret-  (ContractEnv(..), InterpretUntypedError(..), InterpretUntypedResult(..), InterpreterState(..),-  MorleyLogs(..), RemainingSteps(..), interpretUntyped)+  (ContractEnv(..), InterpretError(..), InterpretResult(..), InterpreterState(..), MorleyLogs(..),+  RemainingSteps(..), interpretSome) import Michelson.Macro (ParsedOp, expandContract) import qualified Michelson.Parser as P import Michelson.Runtime.GState import Michelson.Runtime.TxData-import Michelson.TypeCheck (SomeContract, TCError, typeCheckContract)+import Michelson.TypeCheck+  (SomeContract, StorageOrParameter(..), TCError, typeCheckContract, typeCheckStorageOrParameter) import Michelson.Typed-  (CreateContract(..), Operation'(..), TransferTokens(..), convertContract, untypeValue)+  (CreateContract(..), Operation'(..), SomeValue'(..), TransferTokens(..), convertContract,+  untypeValue) import qualified Michelson.Typed as T import Michelson.Untyped (Contract, OriginationOperation(..), mkContractAddress) import qualified Michelson.Untyped as U import Tezos.Address (Address(..))-import Tezos.Core (Mutez, Timestamp(..), getCurrentTime, unsafeAddMutez, unsafeSubMutez)+import Tezos.Core (Mutez, Timestamp(..), getCurrentTime, toMutez, unsafeAddMutez, unsafeSubMutez) import Tezos.Crypto (parseKeyHash) import Util.IO (readFileUtf8) @@ -84,7 +86,7 @@   -- ^ List of operations to be added to the operations queue.   , _irUpdates :: ![GStateUpdate]   -- ^ Updates applied to 'GState'.-  , _irInterpretResults :: [(Address, InterpretUntypedResult)]+  , _irInterpretResults :: [(Address, InterpretResult)]   -- ^ During execution a contract can print logs and in the end it returns   -- a pair. All logs and returned values are kept until all called contracts   -- are executed. In the end they are printed.@@ -102,13 +104,10 @@ -- and get a new one after performing some operations. instance Semigroup InterpreterRes where   a <> b =-    InterpreterRes-      { _irGState = _irGState b-      , _irOperations = _irOperations b-      , _irUpdates = _irUpdates a <> _irUpdates b+    b+      { _irUpdates = _irUpdates a <> _irUpdates b       , _irInterpretResults = _irInterpretResults a <> _irInterpretResults b       , _irSourceAddress = _irSourceAddress a <|> _irSourceAddress b-      , _irRemainingSteps = _irRemainingSteps b       }  -- | Errors that can happen during contract interpreting.@@ -118,7 +117,7 @@   = IEUnknownContract !a   -- ^ The interpreted contract hasn't been originated.   | IEInterpreterFailed !a-                        !InterpretUntypedError+                        !InterpretError   -- ^ Interpretation of Michelson contract failed.   | IEAlreadyOriginated !a                         !ContractState@@ -129,10 +128,16 @@   -- ^ Manager address is unknown.   | IENotEnoughFunds !a !Mutez   -- ^ Sender doesn't have enough funds.+  | IEZeroTransaction !a+  -- ^ Sending 0tz towards an address.   | IEFailedToApplyUpdates !GStateUpdateError   -- ^ Failed to apply updates to GState.   | IEIllTypedContract !TCError   -- ^ A contract is ill-typed.+  | IEIllTypedStorage !TCError+  -- ^ Contract storage is ill-typed+  | IEIllTypedParameter !TCError+  -- ^ Contract parameter is ill-typed   deriving (Show)  instance (Buildable a) => Buildable (InterpreterError' a) where@@ -149,8 +154,12 @@       IENotEnoughFunds addr amount ->         "The sender (" +| addr |+         ") doesn't  have enough funds (has only " +| amount |+ ")"+      IEZeroTransaction addr ->+        "Transaction of 0ꜩ towards a key address " +| addr |+ " which has no code is prohibited"       IEFailedToApplyUpdates err -> "Failed to update GState: " +| err |+ ""-      IEIllTypedContract err -> "The contract is ill-typed " +| err |+ ""+      IEIllTypedContract err -> "The contract is ill-typed: " +| err |+ ""+      IEIllTypedStorage err -> "The contract storage is ill-typed: " +| err |+ ""+      IEIllTypedParameter err -> "The contract parameter is ill-typed: " +| err |+ ""  type InterpreterError = InterpreterError' Address @@ -224,10 +233,8 @@       either (error . mappend "runContract can't parse delegate: " . pretty) id $       parseKeyHash "tz1YCABRTa6H8PLKx2EtDWeCGPaKxUhNgv47"     origination = OriginationOperation-      { ooManager = genesisKeyHash+      { ooOriginator = genesisAddress       , ooDelegate = Just delegate-      , ooSpendable = False-      , ooDelegatable = False       , ooBalance = initBalance       , ooStorage = storageValue       , ooContract = contract@@ -278,8 +285,8 @@     writeGState dbPath _irGState   where     printInterpretResult-      :: (Address, InterpretUntypedResult) -> IO ()-    printInterpretResult (addr, InterpretUntypedResult {..}) = do+      :: (Address, InterpretResult) -> IO ()+    printInterpretResult (addr, InterpretResult {..}) = do       putTextLn $ "Executed contract " <> pretty addr       case iurOps of         [] -> putTextLn "It didn't return any operations"@@ -318,7 +325,10 @@      step :: InterpreterRes -> InterpreterOp -> Either InterpreterError InterpreterRes     step currentRes op =-      let start = currentRes { _irOperations = [op] }+      let start = currentRes { _irOperations = [op]+                             , _irUpdates = []+                             , _irInterpretResults = []+                             }        in (currentRes <>) <$> runExcept (execStateT (statefulInterpreter now) start)  statefulInterpreter@@ -349,9 +359,12 @@   -> InterpreterOp   -> Either InterpreterError InterpreterRes interpretOneOp _ remainingSteps _ gs (OriginateOp origination) = do-  void $ first IEIllTypedContract $+  typedContract <- first IEIllTypedContract $     typeCheckContract (extractAllContracts gs) (ooContract origination)-  let originatorAddress = KeyAddress (ooManager origination)+  typedStorage <- first IEIllTypedStorage $+    typeCheckStorageOrParameter Storage (ooStorage origination)+    (extractAllContracts gs) (ooContract origination)+  let originatorAddress = ooOriginator origination   originatorBalance <- case gsAddresses gs ^. at (originatorAddress) of     Nothing -> Left (IEUnknownManager originatorAddress)     Just (asBalance -> oldBalance)@@ -363,11 +376,12 @@         Right (oldBalance `unsafeSubMutez` ooBalance origination)   let     updates =-      [ GSAddAddress address (ASContract contractState)+      [ GSAddAddress address (ASContract $ mkContractState typedContract typedStorage)       , GSSetBalance originatorAddress originatorBalance       ]   case applyUpdates updates gs of-    Left _ -> Left (IEAlreadyOriginated address contractState)+    Left _ ->+      Left (IEAlreadyOriginated address $ mkContractState typedContract typedStorage)     Right newGS -> Right $       InterpreterRes       { _irGState = newGS@@ -378,24 +392,35 @@       , _irRemainingSteps = remainingSteps       }   where-    contractState = ContractState+    mkContractState typedContract typedStorage = ContractState       { csBalance = ooBalance origination       , csStorage = ooStorage origination       , csContract = ooContract origination+      , csTypedContract = Just typedContract+      , csTypedStorage = Just typedStorage       }     address = mkContractAddress origination interpretOneOp now remainingSteps mSourceAddr gs (TransferOp addr txData) = do     let sourceAddr = fromMaybe (tdSenderAddress txData) mSourceAddr     let senderAddr = tdSenderAddress txData-    decreaseSenderBalance <- case addresses ^. at senderAddr of-      Nothing -> Left (IEUnknownSender senderAddr)-      Just (asBalance -> balance)+    let isKeyAddress (KeyAddress _) = True+        isKeyAddress _  = False+    let isZeroTransfer = tdAmount txData == toMutez 0++    -- Transferring 0 XTZ to a key address is prohibited.+    when (isZeroTransfer && isKeyAddress addr) $+      Left (IEZeroTransaction addr)++    mDecreaseSenderBalance <- case (isZeroTransfer, addresses ^. at senderAddr) of+      (True, _) -> pure Nothing+      (False, Nothing) -> Left (IEUnknownSender senderAddr)+      (False, Just (asBalance -> balance))         | balance < tdAmount txData ->           Left (IENotEnoughFunds senderAddr balance)         | otherwise ->           -- Subtraction is safe because we have checked its           -- precondition in guard.-          Right (GSSetBalance senderAddr (balance `unsafeSubMutez` tdAmount txData))+          Right (Just $ GSSetBalance senderAddr (balance `unsafeSubMutez` tdAmount txData))     let onlyUpdates updates = Right (updates, [], Nothing, remainingSteps)     (otherUpdates, sideEffects, maybeInterpretRes, newRemSteps)         <- case (addresses ^. at addr, addr) of@@ -403,7 +428,8 @@         Left (IEUnknownContract addr)       (Nothing, KeyAddress _) -> do         let-          addrState = ASSimple (tdAmount txData)+          transferAmount = tdAmount txData+          addrState = ASSimple transferAmount           upd = GSAddAddress addr addrState         onlyUpdates [upd]       (Just (ASSimple oldBalance), _) -> do@@ -426,30 +452,39 @@             , ceSource = sourceAddr             , ceSender = senderAddr             , ceAmount = tdAmount txData+            , ceChainId = gsChainId gs             }-        iur@InterpretUntypedResult+        typedParameter <- first IEIllTypedParameter $+           typeCheckStorageOrParameter Parameter (tdParameter txData) existingContracts contract+        typedStorage <- first IEIllTypedStorage $ getTypedStorage gs cs+        typedContract <- first IEIllTypedContract $ getTypedContract gs cs+        iur@InterpretResult           { iurOps = sideEffects           , iurNewStorage = newValue           , iurNewState = InterpreterState _ newRemainingSteps           }           <- first (IEInterpreterFailed addr) $-                interpretUntyped contract (tdParameter txData)-                                 (csStorage cs) contractEnv+                interpretSome typedContract typedParameter+                typedStorage contractEnv         let           newValueU = untypeValue newValue           -- can't overflow if global state is correct (because we can't           -- create money out of nowhere)           newBalance = csBalance cs `unsafeAddMutez` tdAmount txData-          updBalance = GSSetBalance addr newBalance-          updStorage = GSSetStorageValue addr newValueU-          updates =+          updBalance+            | newBalance == csBalance cs = Nothing+            | otherwise = Just $ GSSetBalance addr newBalance+          updStorage+            | SomeValue newValue == typedStorage = Nothing+            | otherwise = Just $ GSSetStorageValue addr newValueU (SomeValue newValue)+          updates = catMaybes             [ updBalance             , updStorage             ]         Right (updates, sideEffects, Just iur, newRemainingSteps)      let-      updates = decreaseSenderBalance:otherUpdates+      updates = maybe id (:) mDecreaseSenderBalance otherUpdates      newGState <- first IEFailedToApplyUpdates $ applyUpdates updates gs @@ -485,22 +520,23 @@ convertOp interpretedAddr =   \case     OpTransferTokens tt ->-      let txData =-            TxData-              { tdSenderAddress = interpretedAddr-              , tdParameter = untypeValue (ttContractParameter tt)-              , tdAmount = ttAmount tt-              }-          T.VContract destAddress = ttContract tt-       in Just (TransferOp destAddress txData)+      case ttContract tt of+        T.VContract destAddress (T.SomeEpc epc) ->+          let fullParam =+                T.compileEpLiftSequence (T.epcLiftSequence epc) $+                ttTransferArgument tt+              txData =+                TxData+                  { tdSenderAddress = interpretedAddr+                  , tdParameter = untypeValue fullParam+                  , tdAmount = ttAmount tt+                  }+          in Just (TransferOp destAddress txData)     OpSetDelegate {} -> Nothing-    OpCreateAccount {} -> Nothing     OpCreateContract cc ->       let origination = OriginationOperation-            { ooManager = ccManager cc+            { ooOriginator = ccOriginator cc             , ooDelegate = ccDelegate cc-            , ooSpendable = ccSpendable cc-            , ooDelegatable = ccDelegatable cc             , ooBalance = ccBalance cc             , ooStorage = untypeValue (ccStorageVal cc)             , ooContract = convertContract (ccContractCode cc)
src/Michelson/Runtime/GState.hs view
@@ -4,11 +4,15 @@        (          -- * Auxiliary types          ContractState (..)+       , getTypedContract+       , getTypedStorage        , AddressState (..)        , asBalance         -- * GState        , GState (..)+       , gsChainIdL+       , gsAddressesL        , genesisAddresses        , genesisKeyHashes        , genesisAddress@@ -32,7 +36,8 @@        , extractAllContracts        ) where -import Control.Lens (at)+import Control.Lens (at, makeLensesWith)+import Data.Aeson (FromJSON(..), ToJSON(..), object, withObject, (.:), (.=)) import qualified Data.Aeson as Aeson import qualified Data.Aeson.Encode.Pretty as Aeson import Data.Aeson.Options (defaultOptions)@@ -40,15 +45,19 @@ import qualified Data.ByteString.Lazy as LBS import Data.List.NonEmpty ((!!)) import qualified Data.Map.Strict as Map-import Fmt (genericF, (+|), (|+))+import Fmt ((+|), (|+), (||+)) import Formatting.Buildable (Buildable(build)) import System.IO.Error (IOError, isDoesNotExistError) -import Michelson.TypeCheck (TcOriginatedContracts)+import Michelson.TypeCheck+  (SomeContract(..), StorageOrParameter(..), TCError, TcOriginatedContracts, typeCheckContract,+  typeCheckStorageOrParameter)+import Michelson.Typed (SomeValue) import Michelson.Untyped (Contract, Type, Value, para)-import Tezos.Address (Address(..))-import Tezos.Core (Mutez, divModMutezInt)+import Tezos.Address (Address(..), ContractHash)+import Tezos.Core (ChainId, Mutez, divModMutezInt, dummyChainId) import Tezos.Crypto+import Util.Lens  -- | State of a contract with code. data ContractState = ContractState@@ -58,13 +67,47 @@   -- ^ Storage value associated with this contract.   , csContract :: !Contract   -- ^ Contract itself (untyped).-  } deriving (Show, Generic, Eq)+  , csTypedContract :: !(Maybe SomeContract)+  , csTypedStorage :: !(Maybe SomeValue)+  -- ^ We keep typed representation of contract code+  -- and storage in form, that hides their actual type+  -- in order to simplify the rest of the code+  -- (e.g. avoid type parameters for `ContractState` and so on).+  -- They are made optional in order to perform safe parsing+  -- from JSON (we simply return `Nothing` in this parser and use+  -- `getTypedStorage` or `getTypedContract` that optionally typecheck+  -- storage or contract code).+  } -instance Buildable ContractState where-  build = genericF+deriving instance Show ContractState -deriveJSON defaultOptions ''ContractState+instance ToJSON ContractState where+  toJSON ContractState{..} = object+    [ "csBalance" .= csBalance+    , "csStorage" .= csStorage+    , "csContract" .= csContract+    ] +-- These instance is a bit hacky because it is quite painful to+-- write proper JSON instances for typed `Instr` and `Value` so+-- we typecheck untyped representation instead of parsing.+instance FromJSON ContractState where+  parseJSON = withObject "contractstate" $ \o -> do+    csBalance <- o .: "csBalance"+    csStorage <- o .: "csStorage"+    csContract <- o .: "csContract"+    let csTypedContract = Nothing+    let csTypedStorage = Nothing+    return ContractState {..}++instance Buildable ContractState where+  build ContractState{..} =+    "Contractstate:\n csBalance: " +| csBalance |++    "\n  csStorage: " +| csStorage |++    "\n  csContract: " +| csContract |++    "\n  csTypedContract: " +| csTypedContract ||++    "\n  csTypedStorage: " +| csTypedStorage ||+ ""+ -- | State of an arbitrary address. data AddressState   = ASSimple !Mutez@@ -72,7 +115,7 @@   | ASContract !ContractState   -- ^ For contracts with code we store more state represented by   -- 'ContractState'.-  deriving (Show, Generic, Eq)+  deriving (Show, Generic)  instance Buildable AddressState where   build =@@ -92,12 +135,24 @@ -- | Persistent data passed to Morley contracts which can be updated -- as result of contract execution. data GState = GState-  { gsAddresses :: Map Address AddressState+  { gsChainId :: ChainId+  -- ^ Identifier of chain.+  , gsAddresses :: Map Address AddressState   -- ^ All known addresses and their state.   } deriving Show +makeLensesWith postfixLFields ''GState+ deriveJSON defaultOptions ''GState +getTypedContract :: GState -> ContractState -> Either TCError SomeContract+getTypedContract gs ContractState{..} =+  typeCheckContract (extractAllContracts gs) csContract++getTypedStorage :: GState -> ContractState -> Either TCError SomeValue+getTypedStorage gs ContractState{..} =+  typeCheckStorageOrParameter Storage csStorage (extractAllContracts gs) csContract+ -- | Number of genesis addresses. genesisAddressesNum :: Word genesisAddressesNum = 10@@ -142,11 +197,12 @@ initGState :: GState initGState =   GState-  { gsAddresses = Map.fromList+  { gsChainId = dummyChainId+  , gsAddresses = Map.fromList     [ (genesis, ASSimple money)-    | genesis <- toList genesisAddresses-    , let (money, _) = maxBound @Mutez `divModMutezInt` genesisAddressesNum+    | let (money, _) = maxBound @Mutez `divModMutezInt` genesisAddressesNum                     ?: error "Number of genesis addresses is 0"+    , genesis <- toList genesisAddresses     ]   } @@ -186,16 +242,17 @@                  !AddressState   | GSSetStorageValue !Address                       !Value+                      !SomeValue   | GSSetBalance !Address                  !Mutez-  deriving (Show, Eq)+  deriving Show  instance Buildable GStateUpdate where   build =     \case       GSAddAddress addr st ->         "Add address " +| addr |+ " with state " +| st |+ ""-      GSSetStorageValue addr val ->+      GSSetStorageValue addr val _ ->         "Set storage value of address " +| addr |+ " to " +| val |+ ""       GSSetBalance addr balance ->         "Set balance of address " +| addr |+ " to " +| balance |+ ""@@ -219,7 +276,8 @@   \case     GSAddAddress addr st ->       maybeToRight (GStateAddressExists addr) . addAddress addr st-    GSSetStorageValue addr newValue -> setStorageValue addr newValue+    GSSetStorageValue addr newValue newTypedValue ->+      setStorageValue addr newValue newTypedValue     GSSetBalance addr newBalance -> setBalance addr newBalance  -- | Apply a list of 'GStateUpdate's to 'GState'.@@ -236,11 +294,14 @@  -- | Updare storage value associated with given address. setStorageValue ::-     Address -> Value -> GState -> Either GStateUpdateError GState-setStorageValue addr newValue = updateAddressState addr modifier+     Address -> Value -> SomeValue -> GState -> Either GStateUpdateError GState+setStorageValue addr newValue newTypedValue = updateAddressState addr modifier   where     modifier (ASSimple _) = Left (GStateNotContract addr)-    modifier (ASContract cs) = Right $ ASContract $ cs { csStorage = newValue }+    modifier (ASContract cs) = Right $ ASContract $+      cs { csStorage = newValue+         , csTypedStorage = Just newTypedValue+         }  -- | Updare storage value associated with given address. setBalance :: Address -> Mutez -> GState -> Either GStateUpdateError GState@@ -265,9 +326,11 @@  -- | Retrive all contracts stored in GState extractAllContracts :: GState -> TcOriginatedContracts-extractAllContracts = Map.mapMaybe extractContract . gsAddresses+extractAllContracts = Map.fromList . mapMaybe extractContract . toPairs . gsAddresses  where-    extractContract :: AddressState -> Maybe Type+    extractContract :: (Address, AddressState) -> Maybe (ContractHash, Type)     extractContract =-      \case ASSimple {} -> Nothing-            ASContract cs -> Just (para $ csContract cs)+      \case (KeyAddress _, ASSimple {}) -> Nothing+            (KeyAddress _, _) -> error "broken GState"+            (ContractAddress ca, ASContract cs) -> Just (ca, para $ csContract cs)+            (ContractAddress _, _) -> error "broken GState"
src/Michelson/Test.hs view
@@ -8,6 +8,11 @@   , specWithContractL   , specWithTypedContract   , specWithUntypedContract+  , testTreesWithContract+  , testTreesWithContractL+  , testTreesWithUntypedContract+  , testTreesWithTypedContract+  , concatTestTrees   , importUntypedContract    -- * Unit testing@@ -31,11 +36,15 @@   , validate   , setMaxSteps   , setNow+  , branchout+  , (?-)    -- ** Validators   , composeValidators   , composeValidatorsList   , expectAnySuccess+  , expectNoUpdates+  , expectNoStorageUpdates   , expectStorageUpdate   , expectStorageUpdateConst   , expectBalance
src/Michelson/Test/Dummy.hs view
@@ -8,9 +8,9 @@   ) where  import Michelson.Interpret (ContractEnv(..), RemainingSteps)-import Michelson.Runtime.GState (genesisAddress, genesisKeyHash)+import Michelson.Runtime.GState (genesisAddress) import Michelson.Untyped-import Tezos.Core (Timestamp(..), unsafeMkMutez)+import Tezos.Core (Timestamp(..), dummyChainId, unsafeMkMutez)  -- | Dummy timestamp, can be used to specify current `NOW` value or -- maybe something else.@@ -38,6 +38,7 @@   , ceSource = genesisAddress   , ceSender = genesisAddress   , ceAmount = unsafeMkMutez 100+  , ceChainId = dummyChainId   }  -- | 'OriginationOperation' with most data hardcoded to some@@ -48,10 +49,8 @@   -> Contract   -> OriginationOperation dummyOrigination storage contract = OriginationOperation-  { ooManager = genesisKeyHash+  { ooOriginator = genesisAddress   , ooDelegate = Nothing-  , ooSpendable = False-  , ooDelegatable = False   , ooBalance = unsafeMkMutez 100   , ooStorage = storage   , ooContract = contract
src/Michelson/Test/Gen.hs view
@@ -72,5 +72,5 @@  instance Arbitrary Timestamp where   arbitrary =-    timestampFromSeconds @Int <$>+    timestampFromSeconds <$>     choose (timestampToSeconds minTimestamp, timestampToSeconds maxTimestamp)
src/Michelson/Test/Import.hs view
@@ -1,14 +1,25 @@ -- | Functions to import contracts to be used in tests.  module Michelson.Test.Import-  ( readContract+  (+    -- * Read, parse, typecheck+    readContract+  , importContract+  , importUntypedContract+  , ImportContractError (..)++    -- * Tasty helpers+  , testTreesWithContract+  , testTreesWithContractL+  , testTreesWithTypedContract+  , testTreesWithUntypedContract+  , concatTestTrees++    -- * HSpec helpers   , specWithContract   , specWithContractL   , specWithTypedContract   , specWithUntypedContract-  , importContract-  , importUntypedContract-  , ImportContractError (..)   ) where  import Control.Exception (IOException)@@ -16,20 +27,78 @@ import Data.Typeable ((:~:)(..), eqT) import Fmt (Buildable(build), pretty, (+|), (|+)) import Test.Hspec (Spec, describe, expectationFailure, it, runIO)+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (assertFailure, testCase)  import qualified Lorentz as L import Michelson.Parser.Error (ParserException(..)) import Michelson.Runtime (parseExpandContract, prepareContract) import Michelson.TypeCheck (SomeContract(..), TCError, typeCheckContract)-import Michelson.Typed (Contract, ToT, toUType)+import Michelson.Typed (Contract, FullContract(..), ToT, toUType) import qualified Michelson.Untyped as U import Util.IO +----------------------------------------------------------------------------+-- tasty helpers+----------------------------------------------------------------------------++-- | Import contract and use to create test trees. Both versions of contract are+-- passed to the callback function (untyped and typed).+--+-- If contract's import fails, a tree with single failing test will be generated+-- (so test tree will likely be generated unexceptionally, but a failing+-- result will notify about problem).+testTreesWithContract+  :: (Each [Typeable, SingI] [cp, st], HasCallStack)+  => FilePath -> ((U.Contract, Contract cp st) -> IO [TestTree]) -> IO [TestTree]+testTreesWithContract = testTreesWithContractImpl importContract++-- | Like 'testTreesWithContract' but for Lorentz types.+testTreesWithContractL+  :: (Each [Typeable, SingI] [ToT cp, ToT st], HasCallStack)+  => FilePath -> ((U.Contract, L.Contract cp st) -> IO [TestTree]) -> IO [TestTree]+testTreesWithContractL file testImpl = testTreesWithContract file (testImpl . second L.I)++-- | Like 'testTreesWithContract' but supplies only untyped contract.+testTreesWithUntypedContract+  :: HasCallStack+  => FilePath -> (U.Contract -> IO [TestTree]) -> IO [TestTree]+testTreesWithUntypedContract =+  testTreesWithContractImpl importUntypedContract++-- | Like 'testTreesWithContract' but supplies only typed contract.+testTreesWithTypedContract+  :: (Each [Typeable, SingI] [cp, st], HasCallStack)+  => FilePath -> (Contract cp st -> IO [TestTree]) -> IO [TestTree]+testTreesWithTypedContract =+  testTreesWithContractImpl (fmap snd . importContract)++testTreesWithContractImpl+  :: HasCallStack+  => (FilePath -> IO contract)+  -> FilePath+  -> (contract -> IO [TestTree])+  -> IO [TestTree]+testTreesWithContractImpl doImport file testImpl =+  saferImport doImport file >>= \case+    Left err -> pure [testCase ("Import contract " <> file) $ assertFailure err]+    Right contract -> testImpl contract++-- A helper function which allows you to use multiple+-- 'testTreesWithTypedContract' in a single top-level test with type+-- 'IO [TestTree]'.+concatTestTrees :: [IO [TestTree]] -> IO [TestTree]+concatTestTrees = fmap concat . sequence++----------------------------------------------------------------------------+-- hspec helpers+----------------------------------------------------------------------------+ -- | Import contract and use it in the spec. Both versions of contract are -- passed to the callback function (untyped and typed). ----- If contract's import failed, a spec with single failing expectation--- will be generated (so tests will run unexceptionally, but a failing+-- If contract's import fails, a spec with single failing expectation+-- will be generated (so tests will likely run unexceptionally, but a failing -- result will notify about problem). specWithContract   :: (Each [Typeable, SingI] [cp, st], HasCallStack)@@ -57,13 +126,26 @@   => (FilePath -> IO contract) -> FilePath -> (contract -> Spec) -> Spec specWithContractImpl doImport file execSpec =   either errorSpec (describe ("Test contract " <> file) . execSpec)-    =<< runIO-          ( (Right <$> doImport file)-            `catch` (\(e :: ImportContractError) -> pure $ Left $ displayException e)-            `catch` \(e :: IOException) -> pure $ Left $ displayException e )+    =<< runIO (saferImport doImport file)   where     errorSpec = it ("Import contract " <> file) . expectationFailure +----------------------------------------------------------------------------+-- Helpers+----------------------------------------------------------------------------++-- Catch some errors during contract import, we don't want the whole+-- test suite to crash if something like that happens.+saferImport :: (FilePath -> IO contract) -> FilePath -> IO (Either String contract)+saferImport doImport file =+  ((Right <$> doImport file)+  `catch` \(e :: ImportContractError) -> pure $ Left $ displayException e)+  `catch` \(e :: IOException) -> pure $ Left $ displayException e++----------------------------------------------------------------------------+-- Reading, parsing, typechecking+----------------------------------------------------------------------------+ readContract   :: forall cp st .     Each [Typeable, SingI] [cp, st]@@ -72,7 +154,7 @@   -> Either ImportContractError (U.Contract, Contract cp st) readContract filePath txt = do   contract <- first ICEParse $ parseExpandContract (Just filePath) txt-  SomeContract (instr :: Contract cp' st') _ _+  SomeContract (FullContract (instr :: Contract cp' st') _ _)     <- first ICETypeCheck $ typeCheckContract mempty contract   case (eqT @cp @cp', eqT @st @st') of     (Just Refl, Just Refl) -> pure (contract, instr)
src/Michelson/Test/Integrational.hs view
@@ -26,13 +26,21 @@   , transfer   , validate   , setMaxSteps+  , modifyNow   , setNow+  , rewindTime   , withSender+  , setChainId+  , branchout+  , (?-)+  , offshoot    -- * Validators   , composeValidators   , composeValidatorsList   , expectAnySuccess+  , expectNoUpdates+  , expectNoStorageUpdates   , expectStorageUpdate   , expectStorageUpdateConst   , expectBalance@@ -41,15 +49,15 @@   , expectMichelsonFailed   ) where -import Control.Lens (assign, at, makeLenses, (%=), (.=), (<>=), (?=))-import Control.Monad.Except (Except, runExcept, throwError)+import Control.Lens (assign, at, makeLenses, makeLensesFor, modifying, (%=), (.=), (<>=), (?=))+import Control.Monad.Except (Except, runExcept, throwError, withExcept) import qualified Data.List as List import Data.Map as Map (empty, insert, lookup)-import Fmt (Buildable(..), blockListF, pretty, (+|), (|+))+import Fmt (Buildable(..), blockListF, listF, pretty, (+|), (|+)) import Test.Hspec (Expectation, expectationFailure) import Test.QuickCheck (Property) -import Michelson.Interpret (InterpretUntypedError(..), MichelsonFailed(..), RemainingSteps)+import Michelson.Interpret (InterpretError(..), MichelsonFailed(..), RemainingSteps) import Michelson.Runtime   (InterpreterError, InterpreterError'(..), InterpreterOp(..), InterpreterRes(..), interpreterPure) import Michelson.Runtime.GState@@ -59,7 +67,7 @@ import Michelson.TypeCheck (TCError) import Michelson.Untyped (Contract, OriginationOperation(..), Value, mkContractAddress) import Tezos.Address (Address)-import Tezos.Core (Mutez, Timestamp)+import Tezos.Core (ChainId, Mutez, Timestamp, timestampPlusSeconds, unsafeMkMutez)  ---------------------------------------------------------------------------- -- Some internals (they are here because TH makes our very existence much harder)@@ -80,6 +88,13 @@  makeLenses ''InternalState +-- | When using 'branch' function for building test scenarios - names+-- of branches we are currently within.+newtype ScenarioBranchName = ScenarioBranchName { unTestBranch :: [Text] }++instance Buildable ScenarioBranchName where+  build = mconcat . intersperse "/" . map build . unTestBranch+ ---------------------------------------------------------------------------- -- Interface ----------------------------------------------------------------------------@@ -90,11 +105,11 @@ type IntegrationalValidator = Either (InterpreterError -> Bool) SuccessValidator  -- | Validator for integrational testing that expects successful execution.-type SuccessValidator = (InternalState -> GState -> [GStateUpdate] -> Either ValidationError ())+type SuccessValidator = InternalState -> GState -> [GStateUpdate] -> Either ValidationError ()  -- | A monad inside which integrational tests can be described using -- do-notation.-type IntegrationalScenarioM = StateT InternalState (Except ValidationError)+type IntegrationalScenarioM = StateT InternalState (Except ScenarioError)  -- | A dummy data type that ensures that `validate` is called in the -- end of each scenario. It is intentionally not exported.@@ -125,7 +140,8 @@   | IncorrectStorageUpdate AddressName Text   | InvalidStorage AddressName ExpectedStorage Text   | InvalidBalance AddressName ExpectedBalance Text-  | CustomError Text+  | UnexpectedUpdates (NonEmpty GStateUpdate)+  | CustomValidationError Text   deriving (Show)  instance Buildable ValidationError where@@ -144,18 +160,37 @@     "Expected " +| addr |+ " to have storage " +| expected |+ ", but " +| msg |+ ""   build (InvalidBalance addr (ExpectedBalance expected) msg) =     "Expected " +| addr |+ " to have balance " +| expected |+ ", but " +| msg |+ ""-  build (CustomError msg) = pretty msg+  build (UnexpectedUpdates updates) =+    "Did not expect certain updates, but there are some: " +| listF updates |+ ""+  build (CustomValidationError msg) = pretty msg  instance Exception ValidationError where   displayException = pretty +-- | Overall information about test scenario error.+data ScenarioError = ScenarioError+  { _seBranch :: ScenarioBranchName+  , _seError :: ValidationError+  }++makeLensesFor [("_seBranch", "seBranch")] ''ScenarioError++instance Buildable ScenarioError where+  build (ScenarioError br err) =+    let builtBranch+          | nullScenarioBranch br = ""+          | otherwise = "In '" +| br |+ "' branch:\n"+    in builtBranch <> build err+ -- | Integrational test that executes given operations and validates -- them using given validator. It can fail using 'Expectation' -- capability. -- It starts with 'initGState' and some reasonable dummy values for -- gas limit and current timestamp. You can update blockchain state -- by performing some operations.-integrationalTestExpectation :: IntegrationalScenario -> Expectation+integrationalTestExpectation+  :: HasCallStack+  => IntegrationalScenario -> Expectation integrationalTestExpectation =   integrationalTest (maybe pass (expectationFailure . pretty)) @@ -195,15 +230,27 @@   ops <- use isOperations   iState <- get   let interpret = interpreterPure now maxSteps gState ops-  mUpdatedGState <- lift $ validateResult validator interpret iState+  mUpdatedGState <-+    lift $+    withExcept (ScenarioError emptyScenarioBranch) $+    validateResult validator interpret iState   isOperations .= mempty   whenJust mUpdatedGState $ \newGState -> isGState .= newGState  -- | Make all further interpreter calls (which are triggered by the+-- 'validate' function) use modified timestamp as the current one.+modifyNow :: (Timestamp -> Timestamp) -> IntegrationalScenarioM ()+modifyNow = modifying isNow++-- | Make all further interpreter calls (which are triggered by the -- 'validate' function) use given timestamp as the current one. setNow :: Timestamp -> IntegrationalScenarioM ()-setNow = assign isNow+setNow time = modifyNow (const time) +-- | Increase current time by the given number of seconds.+rewindTime :: Integer -> IntegrationalScenarioM ()+rewindTime interval = modifyNow (flip timestampPlusSeconds interval)+ -- | Make all further interpreter calls (which are triggered by the -- 'validate' function) use given gas limit. setMaxSteps :: RemainingSteps -> IntegrationalScenarioM ()@@ -217,9 +264,63 @@   isSender ?= addr   scenario <* (isSender .= prevSender) +-- | Make all further interpreter calls (which are triggered by the+-- 'validate' function) use given chain id.+setChainId :: ChainId -> IntegrationalScenarioM ()+setChainId = assign (isGState . gsChainIdL)+ putOperation :: InterpreterOp -> IntegrationalScenarioM () putOperation op = isOperations <>= one op +-- | Make branch names for a case when we are not within any branch.+emptyScenarioBranch :: ScenarioBranchName+emptyScenarioBranch = ScenarioBranchName []++-- | Add a new branch element to names provided by inner 'branch' calls.+appendScenarioBranch :: Text -> ScenarioBranchName -> ScenarioBranchName+appendScenarioBranch brName (ScenarioBranchName branches) =+  ScenarioBranchName (brName : branches)++nullScenarioBranch :: ScenarioBranchName -> Bool+nullScenarioBranch (ScenarioBranchName brs) = null brs++-- | Execute multiple testing scenarios independently, basing+-- them on scenario built till this point.+--+-- The following property holds for this function:+--+-- @ pre >> branchout [a, b, c] = branchout [pre >> a, pre >> b, pre >> c] @.+--+-- In case of property failure in one of the branches no following branch is+-- executed.+--+-- Providing empty list of scenarios to this function causes error;+-- we do not require 'NonEmpty' here though for convenience.+branchout :: HasCallStack => [(Text, IntegrationalScenario)] -> IntegrationalScenario+branchout scenarios = do+  st <- get+  res <- lift . forM scenarios $ \(name, scenario) ->+    withExcept (seBranch %~ appendScenarioBranch name) $+    evalStateT scenario st+  case nonEmpty res of+    Nothing -> error "branch: empty list of scenarios provided"+    Just (validated :| _) -> pure validated++-- | Make a tuple with name without extra syntactic noise.+(?-) :: Text -> a -> (Text, a)+(?-) = (,)+infixr 0 ?-++-- | Test given scenario with the state gathered till this moment;+-- if this scenario passes, go on as if it never happened.+offshoot :: Text -> IntegrationalScenario -> IntegrationalScenarioM ()+offshoot name scenario = do+  st <- get+  Validated <- lift $+    withExcept (seBranch %~ appendScenarioBranch name) $+    evalStateT scenario st+  pass+ ---------------------------------------------------------------------------- -- Validators to be used within 'IntegrationalValidator' ----------------------------------------------------------------------------@@ -228,6 +329,21 @@ expectAnySuccess :: SuccessValidator expectAnySuccess _ _ _ = pass +-- | Check that there were no updates.+expectNoUpdates :: SuccessValidator+expectNoUpdates _ _ updates =+  maybe pass (throwError . UnexpectedUpdates) . nonEmpty $ updates++-- | Check that there were no storage updates.+expectNoStorageUpdates :: SuccessValidator+expectNoStorageUpdates _ _ updates =+  maybe pass (throwError . UnexpectedUpdates) . nonEmpty $+  filter isStorageUpdate updates+  where+    isStorageUpdate = \case+      GSSetStorageValue {} -> True+      _ -> False+ -- | Check that storage value is updated for given address. Takes a -- predicate that is used to check the value. --@@ -241,13 +357,13 @@   case List.find checkAddr (reverse updates) of     Nothing -> Left $       IncorrectStorageUpdate (addrToAddrName addr is) "storage wasn't updated"-    Just (GSSetStorageValue _ val) ->+    Just (GSSetStorageValue _ val _) ->       first (IncorrectStorageUpdate (addrToAddrName addr is) . pretty) $       predicate val     -- 'checkAddr' ensures that only 'GSSetStorageValue' can be found     Just _ -> error "expectStorageUpdate: internal error"   where-    checkAddr (GSSetStorageValue addr' _) = addr' == addr+    checkAddr (GSSetStorageValue addr' _ _) = addr' == addr     checkAddr _ = False  -- | Like 'expectStorageUpdate', but expects a constant.@@ -280,16 +396,13 @@ -- | Check that eventually address has some particular balance. expectBalance :: Address -> Mutez -> SuccessValidator expectBalance addr balance is gs _ =-  case gsAddresses gs ^. at addr of-    Nothing ->-      Left $-      InvalidBalance (addrToAddrName addr is) (ExpectedBalance balance) "it's unknown"-    Just (asBalance -> realBalance)-      | realBalance == balance -> pass-      | otherwise ->-        Left $-        InvalidBalance (addrToAddrName addr is) (ExpectedBalance balance) $-        "its actual balance is: " <> pretty realBalance+  let realBalance = maybe (unsafeMkMutez 0) asBalance (gsAddresses gs ^. at addr) in+  if realBalance == balance then pass+  else+    Left+    $ InvalidBalance (addrToAddrName addr is) (ExpectedBalance balance)+    $ "its actual balance is: " <> pretty realBalance+ -- | Compose two success validators. -- -- For example:@@ -338,7 +451,7 @@   }  integrationalTest ::-     (Maybe ValidationError -> res)+     (Maybe ScenarioError -> res)   -> IntegrationalScenario   -> res integrationalTest howToFail scenario =@@ -354,7 +467,7 @@     (Left validateError, Left err)       | validateError err -> pure Nothing     (_, Left err) ->-      doFail $ UnexpectedInterpreterError $ mkError err iState+      doFail $ UnexpectedInterpreterError (mkError err iState)     (Left _, Right _) ->       doFail $ ExpectingInterpreterToFail     (Right validateUpdates, Right ir)@@ -375,5 +488,9 @@       IEUnknownManager addr -> IEUnknownManager $ addrToAddrName addr is       IENotEnoughFunds addr amount ->         IENotEnoughFunds (addrToAddrName addr is) amount+      IEZeroTransaction addr ->+        IEZeroTransaction (addrToAddrName addr is)       IEFailedToApplyUpdates err -> IEFailedToApplyUpdates err       IEIllTypedContract err -> IEIllTypedContract err+      IEIllTypedStorage err -> IEIllTypedStorage err+      IEIllTypedParameter err -> IEIllTypedParameter err
src/Michelson/Text.hs view
@@ -28,16 +28,24 @@   , qqMText   , mt   , DoNotUseTextError+  , symbolToMText+  , labelToMText+  , mtextHeadToUpper   ) where  import Data.Aeson (FromJSON(..), ToJSON(..))+import qualified Data.Char as C import Data.Data (Data) import qualified Data.Text as T+import Data.Vinyl.Derived (Label) import Fmt (Buildable) import GHC.TypeLits (ErrorMessage(..), TypeError)+import qualified Language.Haskell.TH as TH import qualified Language.Haskell.TH.Quote as TH import Test.QuickCheck (Arbitrary(..), choose, listOf) +import Util.TypeLits+ -- | Michelson string value. -- -- This is basically a mere text with limits imposed by the language:@@ -61,7 +69,7 @@ -- to make it compliant with Michelson constraints. newtype MText = MTextUnsafe { unMText :: Text }   deriving stock (Show, Eq, Ord, Data)-  deriving newtype (Semigroup, Monoid, Container, Buildable)+  deriving newtype (Semigroup, Monoid, Container, Buildable, Hashable)  -- | Constraint on literals appearing in Michelson contract code. isMChar :: Char -> Bool@@ -144,8 +152,10 @@       case qqMText s of         Left err -> fail $ toString err         Right txt -> [e| MTextUnsafe (toText @String txt) |]-  , TH.quotePat = \_ ->-      fail "Cannot use this QuasyQuotation at pattern position"+  , TH.quotePat = \s ->+      case qqMText s of+        Left err -> fail $ toString err+        Right txt -> [p| MTextUnsafe $(TH.litP $ TH.StringL txt) |]   , TH.quoteType = \_ ->       fail "Cannot use this QuasyQuotation at type position"   , TH.quoteDec = \_ ->@@ -181,3 +191,25 @@     ( 'Text "`Text` is not isomorphic to Michelson strings," ':$$:       'Text "consider using `MText` type instead"     )++-- | Create a 'MText' from type-level string.+--+-- We assume that no unicode characters are used in plain Haskell code,+-- so unless special tricky manipulations are used this should be safe.+symbolToMText :: forall name. KnownSymbol name => MText+symbolToMText = mkMTextUnsafe $ symbolValT' @name++-- | Create a 'MText' from label.+--+-- We assume that no unicode characters are used in plain Haskell code,+-- so unless special tricky manipulations are used this should be safe.+labelToMText :: KnownSymbol name => Label name -> MText+labelToMText (_ :: Label name) = symbolToMText @name++-- | Leads first character of text to upper case.+--+-- For empty text this will throw an error.+mtextHeadToUpper :: HasCallStack => MText -> MText+mtextHeadToUpper (MTextUnsafe txt) = case T.uncons txt of+  Nothing -> error "Empty text"+  Just (c, cs) -> MTextUnsafe $ T.cons (C.toUpper c) cs
src/Michelson/TypeCheck.hs view
@@ -1,5 +1,6 @@ module Michelson.TypeCheck   ( typeCheckContract+  , typeCheckStorageOrParameter   , typeCheckValue   , typeVerifyValue   , typeCheckList
src/Michelson/TypeCheck/Error.hs view
@@ -1,11 +1,15 @@+{-# LANGUAGE DerivingStrategies #-}++-- | Errors that can occur when some code is being typechecked.+ module Michelson.TypeCheck.Error-  ( TCTypeError (..)+  ( NotEnoughItemsInstr (..)+  , TCTypeError (..)   , TCError (..)   , ExtError (..)   , StackSize (..)   ) where - import Fmt (Buildable(..), listF, pretty, (+|), (+||), (|+), (||+)) import qualified Text.Show (show) @@ -13,11 +17,28 @@ import Michelson.TypeCheck.Types (SomeHST(..)) import qualified Michelson.Typed as T import Michelson.Typed.Annotation (AnnConvergeError(..))-import Michelson.Typed.Extract (TypeConvergeError(..), toUType)-import Michelson.Typed.Print (buildStack)+import Michelson.Typed.Extract (toUType)+import Michelson.Typed.T (buildStack) import Michelson.Untyped (StackFn, Type, Var) import qualified Michelson.Untyped as U+import Tezos.Crypto(CryptoParseError) +-- | Description of the instruction which wants more items on stack+-- than currently present.+data NotEnoughItemsInstr+  = NotEnoughDrop+  | NotEnoughDip+  | NotEnoughDig+  | NotEnoughDug+  deriving stock (Show, Eq)++instance Buildable NotEnoughItemsInstr where+  build = \case+    NotEnoughDrop -> "DROP"+    NotEnoughDip -> "DIP"+    NotEnoughDig -> "DIG"+    NotEnoughDug -> "DUG"+ -- | Data type that represents various errors -- which are related to type system. -- These errors are used to specify info about type check errors@@ -25,30 +46,53 @@ data TCTypeError   = AnnError AnnConvergeError   -- ^ Annotation unify error-  | ExtractionTypeMismatch TypeConvergeError-  -- ^ Notes extraction error   | TypeEqError T.T T.T   -- ^ Type equality error   | StackEqError [T.T] [T.T]   -- ^ Stacks equality error   | UnsupportedTypes [T.T]-  -- ^ Error that happens when some instruction doesn't-  -- have support for some types-  | UnknownType T.T-  -- ^ Error that happens when we meet unknown type-  deriving (Show, Eq)+  -- ^ Error that happens when type cannot be used in the corresponding scope.+  -- Argument of this constructor carries types which, in the aggregate, violate+  -- the restriction (e.g. @timestamp@ and @timestamp@ passed to @MUL@ instruction).+  | InvalidValueType T.T+  -- ^ Error that happens when a `U.Value` is never a valid source for this type+  -- (e.g. @timestamp@ cannot be obtained from a `U.ValueTrue`)+  | NotEnoughItemsOnStack !Word !NotEnoughItemsInstr+  -- ^ There are not enough items on stack to perform a certain instruction.+  | IllegalEntryPoint T.EpNameFromRefAnnError+  -- ^ Invalid entrypoint name provided+  | IllegalParamDecl T.ParamEpError+  | NegativeNat+  -- ^ Natural numbers cannot be negative+  | MutezOverflow+  -- ^ Exceeds the maximal mutez value+  | InvalidAddress T.ParseEpAddressError+  -- ^ Address couldn't be parsed from its textual representation+  | InvalidKeyHash CryptoParseError+  -- ^ KeyHash couldn't be parsed from its textual representation+  | InvalidTimestamp+  -- ^ Timestamp is not RFC339 compliant+  deriving stock (Show, Eq)  instance Buildable TCTypeError where   build (AnnError e) = build e-  build (ExtractionTypeMismatch e) = build e   build (TypeEqError type1 type2) =     "Types not equal: " +| type1 |+ " /= " +| type2 |+ ""   build (StackEqError st1 st2) =     "Stacks not equal: " +| buildStack st1 |+ " /= " +| buildStack st2 |+ ""   build (UnsupportedTypes types) =     "Unsupported types: " +| listF types |+ ""-  build (UnknownType t) =-    "Unknown type `" +| t |+ "`"+  build (InvalidValueType t) =+    "Value type is never a valid `" +| t |+ "`"+  build (NotEnoughItemsOnStack n instr) =+    "Not enough items on stack to " +| instr |+ " " +| n |+ ""+  build (IllegalEntryPoint err) = build err+  build (IllegalParamDecl err) = build err+  build NegativeNat = "Natural number cannot be negative"+  build MutezOverflow = "Exceeds maximal value for mutez"+  build (InvalidAddress e) = build e+  build (InvalidKeyHash e) = build e+  build (InvalidTimestamp) = "Is not a valid RFC3339 timestamp"  -- | Type check error data TCError@@ -77,10 +121,14 @@       "Error occured during contract typecheck: "       +|| msg ||+ (maybe "" (\e -> " " +| e |+ "") typeError)     TCUnreachableCode _ instrs ->-      "Unreachable code: " +| take 3 (toList instrs) |+ " ..."+      "Unreachable code: " +| buildTruncated 3 (toList instrs)     TCExtError (SomeHST t) _ e ->       "Error occured during Morley extension typecheck: "       +| e |+ " on stack " +| t ||+ ""+    where+    buildTruncated k l+      | null (drop k l) = build l+      | otherwise = build (take k l) <> " ..."  instance Buildable U.ExpandedInstr => Show TCError where   show = pretty
src/Michelson/TypeCheck/Ext.hs view
@@ -14,8 +14,9 @@ import Michelson.TypeCheck.Helpers import Michelson.TypeCheck.TypeCheck import Michelson.TypeCheck.Types-import Michelson.Typed (converge, extractNotes, mkUType)+import Michelson.Typed (Notes(..), converge, mkUType, withUType) import qualified Michelson.Typed as T+import Michelson.Typed.Sing (fromSingT) import Michelson.Untyped   (CT(..), ExpandedOp, StackFn, TyVar(..), Type, Var, VarAnn, inPattern, outPattern,   quantifiedVars, varSet)@@ -126,17 +127,21 @@     go m _ U.StkEmpty SNil = pure $ BoundVars m Nothing     go _ _ U.StkEmpty _    = Left $ LengthMismatch s     go _ _ _ SNil        = Left $ LengthMismatch s-    go m n (U.StkCons (TyCon t) ts) ((xt, xann, _) ::& xs) = do-      tann <- first (TypeMismatch s n . ExtractionTypeMismatch) (extractNotes t xt)-      void $ first (TypeMismatch s n . AnnError) (converge tann xann)-      go m (n + 1) ts xs-    go m n (U.StkCons (VarID v) ts) ((xt, xann, _) ::& xs) =-      case lookup v m of-        Nothing -> let t = mkUType xt xann in go (insert v t m) (n + 1) ts xs-        Just t -> do-          tann <- first (TyVarMismatch v t s n . ExtractionTypeMismatch) (extractNotes t xt)-          void $ first (TyVarMismatch v t s n . AnnError) (converge tann xann)-          go m (n + 1) ts xs+    go m n (U.StkCons tyVar ts) ((xt :: Sing xt, xann :: Notes xt, _) ::& xs) =+      let+        handleType :: U.Type -> Either ExtError BoundVars+        handleType t =+          withUType t $ \(tsing :: Sing t, tann :: Notes t) -> do+            Refl <- first+              (\_ -> TypeMismatch s n $ TypeEqError (fromSingT xt) (fromSingT tsing))+              (eqType @xt @t)+            void $ first (TypeMismatch s n . AnnError) (converge tann xann)+            go m (n + 1) ts xs+      in case tyVar of+        TyCon t -> handleType t+        VarID v -> case lookup v m of+          Nothing -> let t = mkUType xt xann in go (insert v t m) (n + 1) ts xs+          Just t -> handleType t  -- | Create stack reference accessing element with a given index. --
src/Michelson/TypeCheck/Helpers.hs view
@@ -17,7 +17,6 @@     , checkEqT     , checkEqHST     , onTypeCheckInstrAnnErr-    , onTypeCheckInstrTypeErr     , onTypeCheckInstrErr     , typeCheckInstrErr     , typeCheckImpl@@ -53,11 +52,10 @@ import Michelson.TypeCheck.TypeCheck import Michelson.TypeCheck.Types import Michelson.Typed-  (CT(..), Instr(..), Notes(..), Notes'(..), Sing(..), T(..), converge, extractNotes, fromSingT,-  fromUType, mkNotes, notesCase, orAnn, withSomeSingT)+  (CT(..), Instr(..), Notes(..), PackedNotes(..), Sing(..), T(..), converge,+   fromSingT, withUType, orAnn, starNotes) import Michelson.Typed.Annotation (AnnConvergeError) import Michelson.Typed.Arith (Add, ArithOp(..), Compare, Mul, Sub, UnaryArithOp(..))-import Michelson.Typed.Extract (TypeConvergeError) import Michelson.Typed.Polymorphic   (ConcatOp, EDivOp(..), GetOp(..), MemOp(..), SizeOp, SliceOp, UpdOp(..)) @@ -110,11 +108,8 @@ -- It extracts field/type annotations and also auto-generates variable -- annotations if variable annotation is not provided as second argument. deriveNsOr :: Notes ('TOr a b) -> VarAnn -> (Notes a, Notes b, VarAnn, VarAnn)-deriveNsOr ons ovn =-  let (an, bn, afn, bfn) =-        notesCase (NStar, NStar, def, def)-          (\(NTOr _ afn_ bfn_ an_ bn_) -> (an_, bn_, afn_, bfn_)) ons-      avn = deriveVN (Un.convAnn afn `orAnn` "left") ovn+deriveNsOr (NTOr _ afn bfn an bn) ovn =+  let avn = deriveVN (Un.convAnn afn `orAnn` "left") ovn       bvn = deriveVN (Un.convAnn bfn `orAnn` "right") ovn    in (an, bn, avn, bvn) @@ -123,10 +118,8 @@ -- It extracts field/type annotations and also auto-generates variable -- annotation for @Some@ case if it is not provided as second argument. deriveNsOption :: Notes ('TOption a) -> VarAnn -> (Notes a, VarAnn)-deriveNsOption ons ovn =-  let (an, fn) = notesCase (NStar, def)-                    (\(NTOption _ fn_ an_) -> (an_, fn_)) ons-      avn = deriveVN (Un.convAnn fn `orAnn` "some") ovn+deriveNsOption (NTOption _ an) ovn =+  let avn = deriveVN "some" ovn    in (an, avn)  convergeHSTEl@@ -251,12 +244,6 @@ onTypeCheckInstrAnnErr instr i msg ei =   onTypeCheckInstrErr instr (SomeHST i) msg (ei `onLeft` AnnError) -onTypeCheckInstrTypeErr-  :: (MonadReader InstrCallStack m, MonadError TCError m, Typeable ts)-  => Un.ExpandedInstr -> HST ts -> Text -> Either TypeConvergeError a -> m a-onTypeCheckInstrTypeErr instr i msg ei =-  onTypeCheckInstrErr instr (SomeHST i) msg (ei `onLeft` ExtractionTypeMismatch)- typeCheckImpl   :: forall inp . Typeable inp   => TcInstrHandler@@ -291,10 +278,15 @@         p ::: b -> do           _ :/ qi <- typeCheckImpl tcInstr rs b           case qi of-            q ::: c ->-              pure $ a :/ Seq (wrap p) q ::: c+            q ::: c -> case q of+              Seq _ _ ->+                pure $ a :/ Seq (wrapWithNotes b (wrap p)) q ::: c+              -- Wrap the RHS if it is a single instruction and not a+              -- sequence+              _ ->+                pure $ a :/ Seq (wrapWithNotes b (wrap p)) (wrapWithNotes c q) ::: c             AnyOutInstr q ->-              pure $ a :/ AnyOutInstr (Seq (wrap p) q)+              pure $ a :/ AnyOutInstr (Seq (wrapWithNotes b (wrap p)) q)          AnyOutInstr instr ->           case rs of@@ -303,6 +295,11 @@             r : rr ->               throwError $ TCUnreachableCode (extractInstrPos r) (r :| rr) +    wrapWithNotes :: HST d -> Instr c d -> Instr c d+    wrapWithNotes h ins = case h of+      ((s, n, _) ::& _) -> InstrWithNotes (PackedNotes n s) ins+      SNil -> ins+     extractInstrPos :: Un.ExpandedOp -> InstrCallStack     extractInstrPos (Un.WithSrcEx cs _) = cs     extractInstrPos _ = def@@ -312,10 +309,9 @@   :: forall t.       (Typeable t, SingI t)   => (Sing t, Notes t) -> Un.Type -> Either TCTypeError ()-compareTypes (_, n) tp = withSomeSingT (fromUType tp) $ \(t :: Sing ct) -> do+compareTypes (_, n) tp = withUType tp $ \(_ :: Sing ct, nt :: Notes ct) -> do   Refl <- eqType @t @ct-  cnotes <- extractNotes tp t `onLeft` ExtractionTypeMismatch-  void $ converge n cnotes `onLeft` AnnError+  void $ converge n nt `onLeft` AnnError  -------------------------------------------- -- Some generic instruction implementation@@ -335,7 +331,7 @@ memImpl instr i@(_ ::& _ ::& rs) vn = do   pos <- ask   case eqType @('Tc q) @('Tc (MemOpKey c)) of-    Right Refl -> pure $ i :/ MEM ::: ((STc SCBool, NStar, vn) ::& rs)+    Right Refl -> pure $ i :/ MEM ::: ((STc SCBool, starNotes, vn) ::& rs)     Left m     -> throwError $       TCFailedOnInstr instr (SomeHST i) "query element type is not equal to set's element type" pos (Just m) @@ -358,7 +354,7 @@   pos <- ask   case eqType @getKey @('Tc (GetOpKey c)) of     Right Refl -> do-      let rn = mkNotes $ NTOption def def vns+      let rn = NTOption def vns       pure $ i :/ GET ::: ((STOption rt, rn, vn) ::& rs)     Left m -> throwError $ TCFailedOnInstr instr (SomeHST i) "wrong key stack type" pos (Just m) @@ -373,11 +369,13 @@     )   => Un.ExpandedInstr   -> HST (updKey ': updParams ': c ': rs)+  -> VarAnn   -> m (SomeInstr inp)-updImpl instr i@(_ ::& _ ::& crs) = do+updImpl instr i@(_ ::& _ ::& cTuple ::& rest) vn = do   pos <- ask   case (eqType @updKey @('Tc (UpdOpKey c)), eqType @updParams @(UpdOpParams c)) of-    (Right Refl, Right Refl) -> pure $ i :/ UPDATE ::: crs+    (Right Refl, Right Refl) ->+      pure $ i :/ UPDATE ::: ((cTuple & _3 .~ vn) ::& rest)     (Left m, _) -> throwError $ TCFailedOnInstr instr (SomeHST i)                       "wrong key stack type" pos (Just m)     (_, Left m) -> throwError $ TCFailedOnInstr instr (SomeHST i)@@ -388,7 +386,8 @@   => HST inp   -> VarAnn   -> m (SomeInstr inp)-sizeImpl i@(_ ::& rs) vn = pure $ i :/ SIZE ::: ((STc SCNat, NStar, vn) ::& rs)+sizeImpl i@(_ ::& rs) vn =+  pure $ i :/ SIZE ::: ((STc SCNat, starNotes, vn) ::& rs)  sliceImpl   :: (SliceOp c, Typeable c, inp ~ ('Tc 'CNat ': 'Tc 'CNat ': c ': rs), Monad m)@@ -397,7 +396,7 @@   -> m (SomeInstr inp) sliceImpl i@(_ ::& _ ::& (c, cn, cvn) ::& rs) vn = do   let vn' = vn `orAnn` deriveVN "slice" cvn-      rn = mkNotes $ NTOption def def cn+      rn = NTOption def cn   pure $ i :/ SLICE ::: ((STOption c, rn, vn') ::& rs)  concatImpl'@@ -405,9 +404,8 @@   => HST inp   -> Un.VarAnn   -> m (SomeInstr inp)-concatImpl' i@((STList c, ln, _) ::& rs) vn = do-  let cn = notesCase NStar (\(NTList _ n) -> n) ln-  pure $ i :/ CONCAT' ::: ((c, cn, vn) ::& rs)+concatImpl' i@((STList c, NTList _ n, _) ::& rs) vn = do+  pure $ i :/ CONCAT' ::: ((c, n, vn) ::& rs)  concatImpl   :: ( ConcatOp c, Typeable c, inp ~ (c ': c ': rs)@@ -434,7 +432,8 @@   -> HST inp   -> VarAnn   -> t (SomeInstr inp)-arithImpl mkInstr i@(_ ::& _ ::& rs) vn = pure $ i :/ mkInstr ::: ((sing, NStar, vn) ::& rs)+arithImpl mkInstr i@(_ ::& _ ::& rs) vn = do+  pure $ i :/ mkInstr ::: ((sing, starNotes, vn) ::& rs)  addImpl   :: forall a b inp rs m.@@ -493,8 +492,8 @@   => HST inp   -> VarAnn   -> t (SomeInstr inp)-edivImplDo i@(_ ::& _ ::& rs) vn =-  pure $ i :/ EDIV ::: ((sing, NStar, vn) ::& rs)+edivImplDo i@(_ ::& _ ::& rs) vn = do+  pure $ i :/ EDIV ::: ((sing, starNotes, vn) ::& rs)  subImpl   :: forall a b inp rs m.@@ -542,29 +541,25 @@   (Left $ UnsupportedTypes [demote @('Tc a), demote @('Tc b)])  compareImpl-  :: forall a b inp rs m.+  :: forall a inp rs m.      ( Typeable rs-     , Each [Typeable, SingI] [a, b]-     , inp ~ ('Tc a ': 'Tc b ': rs)+     , With [Typeable, SingI] a+     , inp ~ ('Tc a ': 'Tc a ': rs)      , MonadReader InstrCallStack m-     , MonadError TCError m      )-  => Sing a -> Sing b+  => Sing a   -> HST inp   -> VarAnn   -> m (SomeInstr inp)-compareImpl SCBool SCBool = arithImpl @Compare COMPARE-compareImpl SCNat SCNat = arithImpl @Compare COMPARE-compareImpl SCAddress SCAddress = arithImpl @Compare COMPARE-compareImpl SCInt SCInt = arithImpl @Compare COMPARE-compareImpl SCString SCString = arithImpl @Compare COMPARE-compareImpl SCBytes SCBytes = arithImpl @Compare COMPARE-compareImpl SCTimestamp SCTimestamp = arithImpl @Compare COMPARE-compareImpl SCKeyHash SCKeyHash = arithImpl @Compare COMPARE-compareImpl SCMutez SCMutez = arithImpl @Compare COMPARE-compareImpl _ _ = \i vn -> onTypeCheckInstrErr (Un.COMPARE vn) (SomeHST i)-  "wrong operand types for compare operation"-  (Left $ UnsupportedTypes [demote @('Tc a), demote @('Tc b)])+compareImpl SCBool = arithImpl @Compare COMPARE+compareImpl SCNat = arithImpl @Compare COMPARE+compareImpl SCAddress = arithImpl @Compare COMPARE+compareImpl SCInt = arithImpl @Compare COMPARE+compareImpl SCString = arithImpl @Compare COMPARE+compareImpl SCBytes = arithImpl @Compare COMPARE+compareImpl SCTimestamp = arithImpl @Compare COMPARE+compareImpl SCKeyHash = arithImpl @Compare COMPARE+compareImpl SCMutez = arithImpl @Compare COMPARE  -- | Helper function to construct instructions for binary arithmetic -- operations.@@ -579,5 +574,5 @@   -> HST inp   -> VarAnn   -> t (SomeInstr inp)-unaryArithImpl mkInstr i@(_ ::& rs) vn =-  pure $ i :/ mkInstr ::: ((sing, NStar, vn) ::& rs)+unaryArithImpl mkInstr i@(_ ::& rs) vn = do+  pure $ i :/ mkInstr ::: ((sing, starNotes, vn) ::& rs)
src/Michelson/TypeCheck/Instr.hs view
@@ -29,6 +29,8 @@     , typeCheckValue     , typeVerifyValue     , typeCheckList+    , typeCheckStorageOrParameter+    , StorageOrParameter (..)     ) where  import Prelude hiding (EQ, GT, LT)@@ -49,10 +51,7 @@ import Michelson.TypeCheck.Value  import Michelson.Typed-  (Abs, And, CT(..), Contract, ContractOut1, Eq', Ge, Gt, Instr(..), IterOp(..), Le, Lsl, Lsr, Lt,-  MapOp(..), Neg, Neq, Not, Notes(..), Notes'(..), Or, Sing(..), T(..), Value, Value'(..), Xor,-  bigMapAbsense, bigMapConstrained, converge, convergeAnns, extractNotes, fromUType, mkNotes,-  notesCase, opAbsense, orAnn, withSomeSingCT, withSomeSingT)+import Util.Peano  import qualified Michelson.Untyped as U import Michelson.Untyped.Annotation (VarAnn)@@ -69,46 +68,46 @@ typeCheckContractImpl (U.Contract mParam mStorage pCode) = do   code <- maybe (throwError $ TCContractError "no instructions in contract code" Nothing)                 pure (nonEmpty pCode)-  withSomeSingT (fromUType mParam) $ \(paramS :: Sing param) ->-    withSomeSingT (fromUType mStorage) $ \(storageS :: Sing st) -> do-      storageNote <--        liftEither $ extractNotes mStorage storageS `onLeft`-        (TCContractError "failed to extract annotations for storage:" . Just . ExtractionTypeMismatch)-      paramNote <--        liftEither $ extractNotes mParam paramS `onLeft`-        (TCContractError "failed to extract annotations for parameter:" . Just . ExtractionTypeMismatch)-      Dict <--        note (hasTypeError "parameter" (Proxy @'TOperation)) $-        opAbsense paramS-      Dict <--        note (hasTypeError "storage" (Proxy @'TOperation)) $-        opAbsense storageS-      Dict <--        note (hasTypeError "parameter" (Proxy @param)) $-        bigMapAbsense paramS-      Dict <--        note (hasTypeError "storage" (Proxy @st)) $-        bigMapConstrained storageS-      let inpNote = mkNotes (NTPair def def def paramNote storageNote)+  withUType mParam $ \(paramS :: Sing param, paramNote :: Notes param) ->+    withUType mStorage $ \(storageS :: Sing st, storageNote :: Notes st) -> do+      (Dict, Dict) <-+        note (hasTypeError "parameter" paramS) $+          (,) <$> opAbsense paramS+              <*> nestedBigMapsAbsense paramS+      (Dict, Dict, Dict) <-+        note (hasTypeError "storage" storageS) $+          (,,) <$> opAbsense storageS+               <*> nestedBigMapsAbsense storageS+               <*> contractTypeAbsense storageS+      let inpNote = NTPair def def def paramNote storageNote       let inp = (STPair paramS storageS, inpNote, def) ::& SNil       inp' :/ instrOut <- typeCheckNE code inp+      let (paramNotesRaw, fcStoreNotes) = case inp' of+            (_, NTPair _ _ _ cpNotes stNotes, _) ::& SNil -> (cpNotes, stNotes)+      fcParamNotesSafe <-+        liftEither $+        mkParamNotes paramNotesRaw `onLeft`+        (TCContractError "invalid parameter declaration: " . Just . IllegalParamDecl)       case instrOut of         instr ::: out -> liftEither $ do           case eqHST1 @(ContractOut1 st) out of             Right Refl -> do               let (_, outN, _) ::& SNil = out-              _ <- converge outN (N $ NTPair def def def NStar storageNote)+              _ <- converge outN (NTPair def def def starNotes storageNote)                       `onLeft`                   ((TCContractError "contract output type violates convention:") . Just . AnnError)-              pure $ SomeContract instr inp' out+              pure $ SomeContract FullContract+                { fcCode = instr+                , fcParamNotesSafe, fcStoreNotes+                }             Left err -> Left $ TCContractError "contract output type violates convention:" $ Just err-        AnyOutInstr instr -> do-          let outNote = mkNotes (NTPair def def def NStar storageNote)-          let out = (STPair (STList STOperation) storageS, outNote, def)-                      ::& SNil-          pure $ SomeContract instr inp' out+        AnyOutInstr instr ->+          pure $ SomeContract FullContract+            { fcCode = instr+            , fcParamNotesSafe, fcStoreNotes+            }   where-    hasTypeError name (_ :: Proxy t) =+    hasTypeError name (_ :: proxy t) =       TCContractError ("contract " <> name <> " type error") $       Just $ UnsupportedTypes [demote @t] @@ -136,8 +135,8 @@ typeCheckList = usingReaderT def ... typeCheckImpl typeCheckInstr  -- | Function @typeCheckValue@ converts a single Michelson value--- given in representation from @Michelson.Type@ module to representation--- in strictly typed GADT.+-- given in representation from @Michelson.Untyped@ module hierarchy to+-- representation in strictly typed GADT. -- -- As a second argument, @typeCheckValue@ accepts expected type of value. --@@ -150,7 +149,7 @@ typeCheckValue   :: U.Value   -> (Sing t, Notes t)-  -> TypeCheckInstr SomeValue+  -> TypeCheckInstr SomeNotedValue typeCheckValue = typeCheckValImpl typeCheckInstr  -- | Like 'typeCheckValue', but returns value of a desired type.@@ -159,9 +158,42 @@       (Typeable t, SingI t)   => U.Value -> TypeCheckInstr (Value t) typeVerifyValue uval =-  typeCheckValue uval (sing @t, NStar) <&> \case+  typeCheckValue uval (sing @t, starNotes) <&> \case     val :::: _ -> gcast val ?: error "Typechecker produced value of wrong type" +typeCheckStorageOrParameter+  :: StorageOrParameter+  -> U.Value -> TcOriginatedContracts -> U.Contract -> Either TCError SomeValue+typeCheckStorageOrParameter storOrParam valueU originatedContracts U.Contract{..} =+  runTypeCheck para originatedContracts $ usingReaderT (def :: InstrCallStack) $+  typeCheckStorageImpl+  where+    typeCheckStorageImpl =+      let paraOrStor = bool para stor (storOrParam == Storage) in+      withSomeSingT (fromUType paraOrStor) $ \(_ :: Sing t) -> do+          SomeValue <$> typeVerifyValue @t valueU++-- Helper data type we use to typecheck DROPN.+data TCDropHelper inp where+  TCDropHelper ::+    forall (n :: Peano) inp out.+    (Typeable out, SingI n, KnownPeano n, LongerOrSameLength inp n, Drop n inp ~ out) =>+    Sing n -> HST out -> TCDropHelper inp++-- Helper data type we use to typecheck DIG.+data TCDigHelper inp where+  TCDigHelper ::+    forall (n :: Peano) inp out a.+    (Typeable out, ConstraintDIG n inp out a) =>+    Sing n -> HST out -> TCDigHelper inp++-- Helper data type we use to typecheck DUG.+data TCDugHelper inp where+  TCDugHelper ::+    forall (n :: Peano) inp out a.+    (Typeable out, ConstraintDUG n inp out a) =>+    Sing n -> HST out -> TCDugHelper inp+ -- | Function @typeCheckInstr@ converts a single Michelson instruction -- given in representation from @Michelson.Type@ module to representation -- in strictly typed GADT.@@ -181,15 +213,71 @@  typeCheckInstr U.DROP i@(_ ::& rs) = pure (i :/ DROP ::: rs) +typeCheckInstr uInstr@(U.DROPN nTotal) inputHST =+  go nTotal inputHST <&> \case+    TCDropHelper s out -> inputHST :/ DROPN s ::: out+  where+    go :: forall inp. Typeable inp+      => Word+      -> HST inp+      -> TypeCheckInstr (TCDropHelper inp)+    go n i = case (n, i) of+      (0, _) -> pure (TCDropHelper SZ i)++      (_, SNil) -> onTypeCheckInstrErr uInstr+        (SomeHST SNil) "" (Left (NotEnoughItemsOnStack nTotal NotEnoughDrop))++      (_, (_ ::& iTail)) -> do+        go (n - 1) iTail <&> \case TCDropHelper s out -> TCDropHelper (SS s) out+ typeCheckInstr (U.DUP _vn) i@(a ::& rs) =   pure (i :/ DUP ::: (a ::& a::& rs))  typeCheckInstr U.SWAP (i@(a ::& b ::& rs)) =   pure (i :/ SWAP ::: (b ::& a ::& rs)) +typeCheckInstr uInstr@(U.DIG nTotal) inputHST =+  go nTotal inputHST <&> \case+    TCDigHelper s out -> inputHST :/ DIG s ::: out+  where+    go :: forall inp. Typeable inp+      => Word+      -> HST inp+      -> TypeCheckInstr (TCDigHelper inp)+    go n i = case (n, i) of+      -- Even 'DIG 0' is invalid on empty stack (so it is not strictly `Nop`).+      (_, SNil) -> onTypeCheckInstrErr uInstr+        (SomeHST SNil) "" (Left (NotEnoughItemsOnStack nTotal NotEnoughDig))++      (0, (_ ::& _)) -> pure (TCDigHelper SZ i)++      (_, (b ::& iTail)) ->+        go (n - 1) iTail <&> \case+        TCDigHelper s (a ::& resTail) -> TCDigHelper (SS s) (a ::& b ::& resTail)++typeCheckInstr uInstr@(U.DUG nTotal) inputHST =+  go nTotal inputHST <&> \case+    TCDugHelper s out -> inputHST :/ DUG s ::: out+  where+    go :: forall inp. Typeable inp+      => Word+      -> HST inp+      -> TypeCheckInstr (TCDugHelper inp)+    go n i = case (n, i) of+      (0, (_ ::& _)) -> pure (TCDugHelper SZ i)++      (_, (a ::& b ::& iTail)) ->+        go (n - 1) (a ::& iTail) <&> \case+        TCDugHelper s resTail -> TCDugHelper (SS s) (b ::& resTail)++      -- Two cases:+      -- 1. Input stack is empty.+      -- 2. n > 0 and input stack has exactly 1 item.+      _ -> onTypeCheckInstrErr uInstr+        (SomeHST i) "" (Left (NotEnoughItemsOnStack nTotal NotEnoughDug))+ typeCheckInstr instr@(U.PUSH vn mt mval) i =-  withSomeSingT (fromUType mt) $ \t' -> do-    nt' <- onTypeCheckInstrTypeErr instr i "wrong push type:" (extractNotes mt t')+  withUType mt $ \(t' :: Sing t', nt' :: Notes t') -> do     val :::: (t :: Sing t, nt) <- typeCheckValue mval (t', nt')     proofOp <-       maybe (onTypeCheckInstrErr instr (SomeHST i)@@ -201,23 +289,23 @@              "BigMaps in constant are not allowed"              $ Left $ UnsupportedTypes [demote @t])       pure (bigMapAbsense t)-    case (proofOp, proofBigMap) of-      (Dict, Dict) -> pure $ i :/ PUSH val ::: ((t, nt, vn) ::& i)+    proofContract <-+      maybe (onTypeCheckInstrErr instr (SomeHST i)+             "Contract type in constant is not allowed"+             $ Left $ UnsupportedTypes [demote @t])+      pure (contractTypeAbsense t)+    case (proofOp, proofBigMap, proofContract) of+      (Dict, Dict, Dict) -> pure $ i :/ PUSH val ::: ((t, nt, vn) ::& i) -typeCheckInstr (U.SOME tn vn fn) i@((at, an, _) ::& rs) = do-  let n = mkNotes (NTOption tn fn an)-  pure (i :/ SOME ::: ((STOption at, n, vn) ::& rs))+typeCheckInstr (U.SOME tn vn) i@((at, an, _) ::& rs) = do+  pure (i :/ SOME ::: ((STOption at, NTOption tn an, vn) ::& rs)) -typeCheckInstr instr@(U.NONE tn vn fn elMt) i =-  withSomeSingT (fromUType elMt) $ \elT -> do-    let t = STOption elT-    notes <- onTypeCheckInstrTypeErr instr i "wrong none type:"-                (extractNotes (U.Type (U.TOption fn elMt) tn) t)-    pure $ i :/ NONE ::: ((t, notes, vn) ::& i)+typeCheckInstr (U.NONE tn vn elMt) i =+  withUType elMt $ \(elSing :: Sing t, elNotes :: Notes t) ->+    pure $ i :/ NONE ::: ((STOption elSing, NTOption tn elNotes, vn) ::& i)  typeCheckInstr (U.UNIT tn vn) i = do-  let ns = mkNotes $ NTUnit tn-  pure $ i :/ UNIT ::: ((STUnit, ns, vn) ::& i)+  pure $ i :/ UNIT ::: ((STUnit, NTUnit tn, vn) ::& i)  typeCheckInstr (U.IF_NONE mp mq) i@((STOption a, ons, ovn) ::& rs) = do   let (an, avn) = deriveNsOption ons ovn@@ -226,46 +314,40 @@ typeCheckInstr (U.PAIR tn vn pfn qfn) i@((a, an, avn) ::&                                              (b, bn, bvn) ::& rs) = do   let (vn', pfn', qfn') = deriveSpecialFNs pfn qfn avn bvn-      ns = mkNotes $ NTPair tn pfn' qfn' an bn+      ns = NTPair tn pfn' qfn' an bn   pure (i :/ PAIR ::: ((STPair a b, ns, vn `orAnn` vn') ::& rs)) -typeCheckInstr (U.CAR vn _) i@((STPair a _, NStar, _) ::& rs) =-  pure (i :/ CAR ::: ((a, NStar, vn) ::& rs)) typeCheckInstr instr@(U.CAR vn fn)             (i@(( STPair a b-                       , N (NTPair pairTN pfn qfn pns qns)+                       , NTPair pairTN pfn qfn pns qns                        , pairVN ) ::& rs)) = do   pfn' <- onTypeCheckInstrAnnErr instr i "wrong car type:" (convergeAnns fn pfn)   let vn' = deriveSpecialVN vn pfn' pairVN       i' = ( STPair a b-            , N (NTPair pairTN pfn' qfn pns qns)-            , pairVN ) ::& rs-  pure $ i' :/ CAR ::: ((a, pns, vn') ::& rs)+           , NTPair pairTN pfn' qfn pns qns+           , pairVN ) ::& rs+  pure $ i' :/ AnnCAR fn ::: ((a, pns, vn') ::& rs) -typeCheckInstr (U.CDR vn _) i@((STPair _ b, NStar, _) ::& rs) =-  pure (i :/ CDR ::: ((b, NStar, vn) ::& rs)) typeCheckInstr instr@(U.CDR vn fn)           (i@(( STPair a b-                      , N (NTPair pairTN pfn qfn pns qns)+                      , NTPair pairTN pfn qfn pns qns                       , pairVN ) ::& rs)) = do   qfn' <- onTypeCheckInstrAnnErr instr i "wrong cdr type:" (convergeAnns fn qfn)    let vn' = deriveSpecialVN vn qfn' pairVN       i' = ( STPair a b-            , N (NTPair pairTN pfn qfn' pns qns)-            , pairVN ) ::& rs-  pure $ i' :/ CDR ::: ((b, qns, vn') ::& rs)+           , NTPair pairTN pfn qfn' pns qns+           , pairVN ) ::& rs+  pure $ i' :/ AnnCDR fn ::: ((b, qns, vn') ::& rs) -typeCheckInstr instr@(U.LEFT tn vn pfn qfn bMt) i@((a, an, _) ::& rs) =-  withSomeSingT (fromUType bMt) $ \b -> do-    bn <- onTypeCheckInstrTypeErr instr i "wrong left type:" (extractNotes bMt b)-    let ns = mkNotes $ NTOr tn pfn qfn an bn+typeCheckInstr (U.LEFT tn vn pfn qfn bMt) i@((a, an, _) ::& rs) =+  withUType bMt $ \(b :: Sing b, bn :: Notes b) -> do+    let ns = NTOr tn pfn qfn an bn     pure (i :/ LEFT ::: ((STOr a b, ns, vn) ::& rs)) -typeCheckInstr instr@(U.RIGHT tn vn pfn qfn aMt) i@((b, bn, _) ::& rs) =-  withSomeSingT (fromUType aMt) $ \a -> do-    an <- onTypeCheckInstrTypeErr instr i "wrong right type:" (extractNotes aMt a)-    let ns = mkNotes $ NTOr tn pfn qfn an bn+typeCheckInstr (U.RIGHT tn vn pfn qfn aMt) i@((b, bn, _) ::& rs) =+  withUType aMt $ \(a :: Sing a, an :: Notes a) -> do+    let ns = NTOr tn pfn qfn an bn     pure (i :/ RIGHT ::: ((STOr a b, ns, vn) ::& rs))  typeCheckInstr (U.IF_LEFT mp mq) i@((STOr a b, ons, ovn) ::& rs) = do@@ -274,25 +356,22 @@       bit = (b, bn, bvn) ::& rs   genericIf IF_LEFT U.IF_LEFT mp mq ait bit i -typeCheckInstr instr@(U.NIL tn vn elMt) i =-  withSomeSingT (fromUType elMt) $ \elT -> do-    let t = STList elT-    notes <- onTypeCheckInstrTypeErr instr i "wrong nil type:" (extractNotes (U.Type (U.TList elMt) tn) t)-    pure $ i :/ NIL ::: ((t, notes, vn) ::& i)+typeCheckInstr (U.NIL tn vn elMt) i =+  withUType elMt $ \(elT :: Sing elT, elNotes :: Notes elT) ->+    pure $ i :/ NIL ::: ((STList elT, NTList tn elNotes, vn) ::& i)  typeCheckInstr instr@(U.CONS vn) i@((((at :: Sing a), an, _)                               ::& (STList (_ :: Sing a'), ln, _) ::& rs)) =   case eqType @a @a' of     Right Refl -> do-      n <- onTypeCheckInstrAnnErr instr i "wrong cons type:" (converge ln (mkNotes $ NTList def an))+      n <- onTypeCheckInstrAnnErr instr i "wrong cons type:" (converge ln (NTList def an))       pure $ i :/ CONS ::: ((STList at, n, vn) ::& rs)     Left m -> onTypeCheckInstrErr instr (SomeHST i)                 ("list element type is different from one "                 <> "that is being CONSed:") (Left m) - typeCheckInstr (U.IF_CONS mp mq) i@((STList a, ns, vn) ::& rs)  = do-  let an = notesCase NStar (\(NTList _ an_) -> an_) ns+  let NTList _ an = ns       ait =         (a, an, vn <> "hd") ::& (STList a, ns, vn <> "tl") ::& rs   genericIf IF_CONS U.IF_CONS mp mq ait rs i@@ -305,38 +384,47 @@  typeCheckInstr (U.EMPTY_SET tn vn (U.Comparable mk ktn)) i =   withSomeSingCT mk $ \k ->-    pure $ i :/ EMPTY_SET ::: ((STSet k, mkNotes $ NTSet tn ktn, vn) ::& i)+    pure $ i :/ EMPTY_SET ::: ((STSet k, NTSet tn ktn, vn) ::& i) -typeCheckInstr instr@(U.EMPTY_MAP tn vn (U.Comparable mk ktn) mv) i =-  withSomeSingT (fromUType mv) $ \v ->+typeCheckInstr (U.EMPTY_MAP tn vn (U.Comparable mk ktn) mv) i =+  withUType mv $ \(v :: Sing v, vns :: Notes v) ->   withSomeSingCT mk $ \k -> do-    vns <- onTypeCheckInstrTypeErr instr i "wrong empty_map type:" (extractNotes mv v)-    let ns = mkNotes $ NTMap tn ktn vns+    let ns = NTMap tn ktn vns     pure $ i :/ EMPTY_MAP ::: ((STMap k v, ns, vn) ::& i) -typeCheckInstr instr@(U.MAP vn mp) i@((STList _, ns, _vn) ::& _) = do-  let vns = notesCase NStar (\(NTList _ v') -> v') ns+typeCheckInstr (U.EMPTY_BIG_MAP tn vn (U.Comparable mk ktn) mv) i =+  withUType mv $ \(v :: Sing v, vns :: Notes v) ->+  withSomeSingCT mk $ \k -> do+    let ns = NTBigMap tn ktn vns+    pure $ i :/ EMPTY_BIG_MAP ::: ((STBigMap k v, ns, vn) ::& i)++typeCheckInstr instr@(U.MAP vn mp) i@((STList _, NTList _ vns, _vn) ::& _) = do   mapImpl vns instr mp i-    (\rt rn -> (::&) (STList rt, mkNotes $ NTList def rn, vn))+    (\rt rn -> (::&) (STList rt, NTList def rn, vn)) -typeCheckInstr instr@(U.MAP vn mp) i@((STMap k _, ns, _vn) ::& _)  = do-  let (kns, vns) = notesCase (def, NStar) (\(NTMap _ k' v') -> (k', v')) ns-      pns = mkNotes $ NTPair def def def (mkNotes $ NTc kns) vns+typeCheckInstr+  instr@(U.MAP vn mp)+  i@((STMap k _, NTMap _ kns vns, _vn) ::& _)+    = do+  let pns = NTPair def def def (NTc kns) vns   mapImpl pns instr mp i-    (\rt rn -> (::&) (STMap k rt, mkNotes $ NTMap def kns rn, vn))+    (\rt rn -> (::&) (STMap k rt, NTMap def kns rn, vn))  -- case `U.HSTER []` is wrongly typed by definition -- (as it is required to at least drop an element), so we don't consider it -typeCheckInstr instr@(U.ITER (i1 : ir)) i@((STSet _, n, _) ::& _) = do-  let en = notesCase NStar (\(NTSet _ en_) -> mkNotes $ NTc en_) n-  iterImpl en instr (i1 :| ir) i-typeCheckInstr instr@(U.ITER (i1 : ir)) (i@((STList _, n, _) ::& _)) = do-  let en = notesCase NStar (\(NTList _ en_) -> en_) n+typeCheckInstr instr@(U.ITER (i1 : ir)) i@((STSet _, NTSet _ en, _) ::& _) = do+  iterImpl (NTc en) instr (i1 :| ir) i+typeCheckInstr+  instr@(U.ITER (i1 : ir))+  i@((STList _, NTList _ en, _) ::& _)+    = do   iterImpl en instr (i1 :| ir) i-typeCheckInstr instr@(U.ITER (i1 : ir)) (i@((STMap _ _, n, _) ::& _)) = do-  let en = notesCase NStar (\(NTMap _ kns vns) ->-              mkNotes $ NTPair def def def (mkNotes $ NTc kns) vns) n+typeCheckInstr+  instr@(U.ITER (i1 : ir))+  i@((STMap _ _, NTMap _ kns vns, _) ::& _)+    = do+  let en = NTPair def def def (NTc kns) vns   iterImpl en instr (i1 :| ir) i  typeCheckInstr instr@(U.MEM vn)@@ -346,16 +434,20 @@ typeCheckInstr instr@(U.MEM vn)            i@((STc _, _, _) ::& (STBigMap _ _, _, _) ::& _) = memImpl instr i vn -typeCheckInstr instr@(U.GET vn) i@(_ ::& (STMap _ vt, cn, _) ::& _) =-  getImpl instr i vt (notesCase NStar (\(NTMap _ _ v) -> v) cn) vn-typeCheckInstr instr@(U.GET vn) i@(_ ::& (STBigMap _ vt, cn, _) ::& _) =-  getImpl instr i vt (notesCase NStar (\(NTBigMap _ _ v) -> v) cn) vn+typeCheckInstr instr@(U.GET vn) i@(_ ::& (STMap _ vt, NTMap _ _ v, _) ::& _) =+  getImpl instr i vt v vn+typeCheckInstr+  instr@(U.GET vn)+  i@(_ ::& (STBigMap _ vt, NTBigMap _ _ v, _) ::& _)+    =+  getImpl instr i vt v vn -typeCheckInstr instr@U.UPDATE i@(_ ::& _ ::& (STMap _ _, _, _) ::& _) =-  updImpl instr i-typeCheckInstr instr@U.UPDATE i@(_ ::& _ ::& (STBigMap _ _, _, _)-                                             ::& _) = updImpl instr i-typeCheckInstr instr@U.UPDATE i@(_ ::& _ ::& (STSet _, _, _) ::& _) = updImpl instr i+typeCheckInstr instr@(U.UPDATE vn) i@(_ ::& _ ::& (STMap _ _, _, _) ::& _) =+  updImpl instr i vn+typeCheckInstr instr@(U.UPDATE vn) i@(_ ::& _ ::& (STBigMap _ _, _, _) ::& _) =+  updImpl instr i vn+typeCheckInstr instr@(U.UPDATE vn) i@(_ ::& _ ::& (STSet _, _, _) ::& _) =+  updImpl instr i vn  typeCheckInstr (U.IF mp mq) i@((STc SCBool, _, _) ::& rs)  =   genericIf IF U.IF mp mq rs rs i@@ -395,46 +487,83 @@       pure $ i :/ LOOP_LEFT subI ::: (br ::& rs)  typeCheckInstr instr@(U.LAMBDA vn imt omt is) i = do-  withSomeSingT (fromUType imt) $ \(it :: Sing it) -> do-    withSomeSingT (fromUType omt) $ \(ot :: Sing ot) -> do-      ins <- onTypeCheckInstrTypeErr instr i "wrong lambda input type:" (extractNotes imt it)-      ons <- onTypeCheckInstrTypeErr instr i "wrong lambda output type:" (extractNotes omt ot)+  withUType imt $ \(it :: Sing it, ins :: Notes ins) ->+    withUType omt $ \(ot :: Sing ot, ons :: Notes ons) ->       -- further processing is extracted into another function because       -- otherwise I encountered some weird GHC error with that code       -- located right here       lamImpl instr is vn it ins ot ons i  typeCheckInstr instr@(U.EXEC vn) i@(((_ :: Sing t1), _, _)-                              ::& (STLambda (_ :: Sing t1') t2, ln, _)+                              ::& ( STLambda (_ :: Sing t1') t2+                                  , NTLambda _ _ t2n+                                  , _+                                  )                               ::& rs) = do-  let t2n = notesCase NStar (\(NTLambda _ _ n) -> n) ln   Refl <- onTypeCheckInstrErr instr (SomeHST i)                 "lambda is given argument with wrong type:" (eqType @t1 @t1')   pure $ i :/ EXEC ::: ((t2, t2n, vn) ::& rs) +typeCheckInstr instr@(U.APPLY vn)+               i@(((_ :: Sing a'), _, _)+                  ::& (STLambda (STPair (sa :: Sing a) (sb :: Sing b)) sc, ln, _)+                  ::& rs) = do+  let+    l2n = case ln of+      NTLambda vann (NTPair _ _ _ _ bn) cn ->+        NTLambda vann bn cn++  proofArgEq <- onTypeCheckInstrErr instr (SomeHST i)+                "lambda is given argument with wrong type:" (eqType @a' @a)+  proofOp <-+    maybe (onTypeCheckInstrErr instr (SomeHST i)+            "Operations in argument of partially applied lambda are not allowed"+            $ Left $ UnsupportedTypes [demote @a])+    pure (opAbsense sa)+  proofBigMap <-+    maybe (onTypeCheckInstrErr instr (SomeHST i)+            "BigMaps in argument of partially applied lambda are not allowed"+            $ Left $ UnsupportedTypes [demote @a])+    pure (bigMapAbsense sa)+  proofContract <-+    maybe (onTypeCheckInstrErr instr (SomeHST i)+            "Contract type in constant is not allowed"+            $ Left $ UnsupportedTypes [demote @a])+    pure (contractTypeAbsense sa)+  case (proofArgEq, proofOp, proofBigMap, proofContract) of+    (Refl, Dict, Dict, Dict) ->+      pure $ i :/ (APPLY @a) ::: ((STLambda sb sc, l2n, vn) ::& rs)+ typeCheckInstr instr@(U.DIP is) i@(a ::& (s :: HST s)) = do-  _ :/ tp <- lift (typeCheckList is s)-  case tp of-    subI ::: t ->-      pure $ i :/ DIP subI ::: (a ::& t)-    AnyOutInstr _ -> do-      -- This may seem like we throw error because of despair, but in fact,-      -- the reference implementation seems to behave exactly in this way --      -- if output stack of code block within @DIP@ occurs to be any, an-      -- error "FAILWITH must be at tail position" is raised.-      typeCheckInstrErr instr (SomeHST i)-          "Code within DIP instruction always fails, which is not allowed"+  typeCheckDipBody instr is s $ \subI t -> pure $ i :/ DIP subI ::: (a ::& t) +typeCheckInstr uInstr@(U.DIPN nTotal instructions) inputHST =+  go nTotal inputHST <&> \case+  TCDipHelper s subI out -> inputHST :/ DIPN s subI ::: out+  where+    go :: forall inp. Typeable inp+      => Word+      -> HST inp+      -> TypeCheckInstr (TCDipHelper inp)+    go n curHST = case (n, curHST) of+      (0, _) -> typeCheckDipBody uInstr instructions curHST $ \subI t ->+        pure (TCDipHelper SZ subI t)+      (_, SNil) -> onTypeCheckInstrErr uInstr+        (SomeHST SNil) "" (Left (NotEnoughItemsOnStack nTotal NotEnoughDip))+      (_, hstHead ::& hstTail) ->+        go (n - 1) hstTail <&> \case+        TCDipHelper s subI out -> TCDipHelper (SS s) subI (hstHead ::& out)+ typeCheckInstr U.FAILWITH i@(_ ::& _) =   pure $ i :/ AnyOutInstr FAILWITH -typeCheckInstr instr@(U.CAST vn mt)+typeCheckInstr instr@(U.CAST vn castToType)            i@(((e :: Sing e), (en :: Notes e), evn) ::& rs) =-  withSomeSingT (fromUType mt) $ \(_ :: Sing e') -> do-    Refl <- errM (eqType @e @e')-    en' <- errM (extractNotes mt e `onLeft` ExtractionTypeMismatch)-    ns <- errM (converge en en' `onLeft` AnnError)-    pure $ i :/ CAST ::: ((e, ns, vn `orAnn` evn) ::& rs)+  withUType castToType $+    \(_ :: Sing castToType, castToNotes :: Notes castToType) -> do+      Refl <- errM (eqType @e @castToType)+      void $ errM (converge en castToNotes `onLeft` AnnError)+      pure $ i :/ CAST ::: ((e, castToNotes, vn `orAnn` evn) ::& rs)   where     errM :: (MonadReader InstrCallStack m, MonadError TCError m) => Either TCTypeError a -> m a     errM = onTypeCheckInstrErr instr (SomeHST i) "cast to incompatible type:"@@ -443,9 +572,8 @@   pure $ i :/ RENAME ::: ((at, an, vn) ::& rs)  typeCheckInstr instr@(U.UNPACK vn mt) i@((STc SCBytes, _, _) ::& rs) =-  withSomeSingT (fromUType mt) $ \t -> do-    tns <- onTypeCheckInstrTypeErr instr i "wrong unpack type" (extractNotes mt t)-    let ns = mkNotes $ NTOption def def tns+  withUType mt $ \(t :: Sing t, tns :: Notes t) -> do+    let ns = NTOption def tns     proofOp <-       maybe (typeCheckInstrErr instr (SomeHST i)              "Operation cannot appear in serialized data")@@ -454,8 +582,12 @@       maybe (typeCheckInstrErr instr (SomeHST i)              "BigMap cannot appear in serialized data")       pure (bigMapAbsense t)-    case (proofOp, proofBigMap) of-      (Dict, Dict) -> pure $ i :/ UNPACK ::: ((STOption t, ns, vn) ::& rs)+    proofContract <-+      maybe (typeCheckInstrErr instr (SomeHST i)+             "UNPACK should not contain 'contract' type")+      pure (contractTypeAbsense t)+    case (proofOp, proofBigMap, proofContract) of+      (Dict, Dict, Dict) -> pure $ i :/ UNPACK ::: ((STOption t, ns, vn) ::& rs)  typeCheckInstr instr@(U.PACK vn) i@(((a :: Sing a), _, _) ::& rs) = do   proofOp <-@@ -469,7 +601,7 @@            $ Left $ UnsupportedTypes [demote @a])     pure (bigMapAbsense a)   case (proofOp, proofBigMap) of-    (Dict, Dict) -> pure $ i :/ PACK ::: ((STc SCBytes, NStar, vn) ::& rs)+    (Dict, Dict) -> pure $ i :/ PACK ::: ((STc SCBytes, starNotes, vn) ::& rs)  typeCheckInstr (U.CONCAT vn) i@((STc SCBytes, _, _) ::&                                     (STc SCBytes, _, _) ::& _) = concatImpl i vn@@ -486,7 +618,7 @@  typeCheckInstr (U.ISNAT vn') i@((STc SCInt, _, oldVn) ::& rs) = do   let vn = vn' `orAnn` oldVn-  pure $ i :/ ISNAT ::: ((STOption (STc SCNat), NStar, vn) ::& rs)+  pure $ i :/ ISNAT ::: ((STOption (STc SCNat), starNotes, vn) ::& rs)  typeCheckInstr (U.ADD vn) i@((STc a, _, _) ::&                                  (STc b, _, _) ::& _) = addImpl a b i vn@@ -502,9 +634,9 @@  typeCheckInstr (U.ABS vn) i@((STc SCInt, _, _) ::& _) = unaryArithImpl @Abs ABS i vn -typeCheckInstr U.NEG (i@((STc SCInt, _, _) ::& _)) = unaryArithImpl @Neg NEG i def+typeCheckInstr (U.NEG vn) (i@((STc SCInt, _, _) ::& _)) = unaryArithImpl @Neg NEG i vn -typeCheckInstr U.NEG (i@((STc SCNat, _, _) ::& _)) = unaryArithImpl @Neg NEG i def+typeCheckInstr (U.NEG vn) (i@((STc SCNat, _, _) ::& _)) = unaryArithImpl @Neg NEG i vn  typeCheckInstr (U.LSL vn) i@((STc SCNat, _, _) ::&                          (STc SCNat, _, _) ::& _) = arithImpl @Lsl LSL i vn@@ -533,8 +665,18 @@ typeCheckInstr (U.NOT vn) i@((STc SCBool, _, _) ::& _) = unaryArithImpl @Not NOT i vn typeCheckInstr (U.NOT vn) i@((STc SCInt, _, _) ::& _) = unaryArithImpl @Not NOT i vn -typeCheckInstr (U.COMPARE vn) i@((STc a, _, _) ::&-                                 (STc b, _, _) ::& _) = compareImpl a b i vn+typeCheckInstr instr@(U.COMPARE vn)+  i@((STc (_ :: Sing aCT), (an :: Notes ('Tc aCT)), _) ::&+     (STc (_ :: Sing bCT), (bn :: Notes ('Tc bCT)), _) ::& _+    ) = do+  Refl <- errM $ eqType @('Tc aCT) @('Tc bCT)+  void . errConv $ converge an bn+  compareImpl (sing @aCT) i vn+  where+    errConv :: (MonadReader InstrCallStack m, MonadError TCError m) => Either AnnConvergeError a -> m a+    errConv = onTypeCheckInstrAnnErr instr i "comparing types with different annotations:"+    errM :: (MonadReader InstrCallStack m, MonadError TCError m) => Either TCTypeError a -> m a+    errM = onTypeCheckInstrErr instr (SomeHST i) "comparing different types:"  typeCheckInstr (U.EQ vn) i@((STc SCInt, _, _) ::& _) = unaryArithImpl @Eq' EQ i vn @@ -549,21 +691,45 @@ typeCheckInstr (U.GE vn) i@((STc SCInt, _, _) ::& _) = unaryArithImpl @Ge GE i vn  typeCheckInstr (U.INT vn) i@((STc SCNat, _, _) ::& rs) =-  pure $ i :/ INT ::: ((STc SCInt, NStar, vn) ::& rs)+  pure $ i :/ INT ::: ((STc SCInt, starNotes, vn) ::& rs) -typeCheckInstr instr@(U.SELF vn) shst@i = do+typeCheckInstr instr@(U.SELF vn) i = do   cpType <- gets tcContractParam   let t = fromUType cpType-  withSomeSingT t $ \(singcp :: Sing cp) -> do-    nt <- onTypeCheckInstrTypeErr instr shst "wrong self type" (extractNotes cpType singcp )-    pure $ i :/ SELF @cp ::: ((sing @('TContract cp), N (NTContract U.noAnn nt), vn) ::& i)+  withUType cpType $ \(singcp :: Sing cp, nt :: Notes cp) -> do+    proofOp <-+      maybe (onTypeCheckInstrErr instr (SomeHST i)+              "contract param type cannot contain operation"+              $ Left $ UnsupportedTypes [t])+      pure (opAbsense singcp)+    proofBigMap <-+      maybe (onTypeCheckInstrErr instr (SomeHST i)+              "contract param type cannot contain nested big_map"+              $ Left $ UnsupportedTypes [t])+      pure (nestedBigMapsAbsense singcp)+    case (proofOp, proofBigMap) of+      (Dict, Dict) -> do+        pure $ i :/ SELF @cp ::: ((sing @('TContract cp), NTContract U.noAnn nt, vn) ::& i) -typeCheckInstr instr@(U.CONTRACT vn mt)+typeCheckInstr instr@(U.CONTRACT vn fn mt)            i@((STc SCAddress, _, _) ::& rs) =-  withSomeSingT (fromUType mt) $ \t -> do-    tns <- onTypeCheckInstrTypeErr instr i "wrong contract command type" (extractNotes mt t)-    let ns = mkNotes $ NTOption def def $ mkNotes $ NTContract def tns-    pure $ i :/ CONTRACT tns ::: ((STOption $ STContract t, ns, vn) ::& rs)+  withUType mt $ \(t :: Sing t, tns :: Notes t) -> do+    proofOp <-+      maybe (onTypeCheckInstrErr instr (SomeHST i)+              "contract param type cannot contain operation"+              $ Left $ UnsupportedTypes [fromUType mt])+      pure (opAbsense t)+    proofBigMap <-+      maybe (onTypeCheckInstrErr instr (SomeHST i)+              "contract param type cannot contain nested big_map"+              $ Left $ UnsupportedTypes [fromUType mt])+      pure (nestedBigMapsAbsense t)+    let ns = NTOption def $ NTContract def tns+    epName <- onTypeCheckInstrErr instr (SomeHST i) "Bad annotation:" $+                epNameFromRefAnn fn `onLeft` IllegalEntryPoint+    case (proofOp, proofBigMap) of+      (Dict, Dict) ->+        pure $ i :/ CONTRACT tns epName ::: ((STOption $ STContract t, ns, vn) ::& rs)  typeCheckInstr instr@(U.TRANSFER_TOKENS vn) i@(((_ :: Sing p'), _, _)   ::& (STc SCMutez, _, _) ::& (STContract (p :: Sing p), _, _) ::& rs) = do@@ -576,88 +742,78 @@     maybe (onTypeCheckInstrErr instr (SomeHST i)             "contract param type cannot contain big_map"             $ Left $ UnsupportedTypes [demote @p])-    pure (bigMapAbsense p)+    pure (nestedBigMapsAbsense p)   case (eqType @p @p', proofOp, proofBigMap) of     (Right Refl, Dict, Dict) ->-      pure $ i :/ TRANSFER_TOKENS ::: ((STOperation, NStar, vn) ::& rs)+      pure $ i :/ TRANSFER_TOKENS ::: ((STOperation, starNotes, vn) ::& rs)     (Left m, _, _) ->       onTypeCheckInstrErr instr (SomeHST i)         "mismatch of contract param type:" (Left m)  typeCheckInstr (U.SET_DELEGATE vn)            i@((STOption (STc SCKeyHash), _, _) ::& rs) = do-  pure $ i :/ SET_DELEGATE ::: ((STOperation, NStar, vn) ::& rs)--typeCheckInstr (U.CREATE_ACCOUNT ovn avn)-           i@((STc SCKeyHash, _, _)-             ::& (STOption (STc SCKeyHash), _, _) ::& (STc SCBool, _, _)-             ::& (STc SCMutez, _, _) ::& rs) =-  pure $ i :/ CREATE_ACCOUNT ::: ((STOperation, NStar, ovn) ::&-                                   (STc SCAddress, NStar, avn) ::& rs)+  pure $ i :/ SET_DELEGATE ::: ((STOperation, starNotes, vn) ::& rs)  typeCheckInstr instr@(U.CREATE_CONTRACT ovn avn contract)-           i@((STc SCKeyHash, _, _)-             ::& (STOption (STc SCKeyHash), _, _)-             ::& (STc SCBool, _, _)-             ::& (STc SCBool, _, _)+           i@((STOption (STc SCKeyHash), _, _)              ::& (STc SCMutez, _, _)              ::& ((_ :: Sing g), gn, _) ::& rs) = do-  (SomeContract (contr :: Contract p' g') _ out) <- lift $ typeCheckContractImpl contract+  (SomeContract (FullContract (contr :: Contract p' g') paramNotes storeNotes))+    <- lift $ typeCheckContractImpl contract   Refl <- checkEqT @g @g' instr i "contract storage type mismatch"-  void $ onTypeCheckInstrAnnErr instr i "contract storage type mismatch" (converge gn (outNotes out) )-  pure $ i :/ CREATE_CONTRACT contr ::: ((STOperation, NStar, ovn) ::&-                                           (STc SCAddress, NStar, avn) ::& rs)-  where-    outNotes :: HST '[ 'TPair ('TList 'TOperation) g' ] -> Notes g'-    outNotes ((_, n, _) ::& SNil) =-      notesCase NStar (\(NTPair _ _ _ _ n') -> n') n+  void $ onTypeCheckInstrAnnErr instr i "contract storage type mismatch" (converge gn storeNotes)+  pure $ i :/ CREATE_CONTRACT (FullContract contr paramNotes storeNotes) :::+         ((STOperation, starNotes, ovn) ::& (STc SCAddress, starNotes, avn) ::& rs)  typeCheckInstr (U.IMPLICIT_ACCOUNT vn)            i@((STc SCKeyHash, _, _) ::& rs) =-  pure $ i :/ IMPLICIT_ACCOUNT ::: ((STContract STUnit, NStar, vn) ::& rs)+  pure $ i :/ IMPLICIT_ACCOUNT ::: ((STContract STUnit, starNotes, vn) ::& rs)  typeCheckInstr (U.NOW vn) i =-  pure $ i :/ NOW ::: ((STc SCTimestamp, NStar, vn) ::& i)+  pure $ i :/ NOW ::: ((STc SCTimestamp, starNotes, vn) ::& i)  typeCheckInstr (U.AMOUNT vn) i =-  pure $ i :/ AMOUNT ::: ((STc SCMutez, NStar, vn) ::& i)+  pure $ i :/ AMOUNT ::: ((STc SCMutez, starNotes, vn) ::& i)  typeCheckInstr (U.BALANCE vn) i =-  pure $ i :/ BALANCE ::: ((STc SCMutez, NStar, vn) ::& i)+  pure $ i :/ BALANCE ::: ((STc SCMutez, starNotes, vn) ::& i)  typeCheckInstr (U.CHECK_SIGNATURE vn)            i@((STKey, _, _)              ::& (STSignature, _, _) ::& (STc SCBytes, _, _) ::& rs) =-  pure $ i :/ CHECK_SIGNATURE ::: ((STc SCBool, NStar, vn) ::& rs)+  pure $ i :/ CHECK_SIGNATURE ::: ((STc SCBool, starNotes, vn) ::& rs)  typeCheckInstr (U.SHA256 vn)            i@((STc SCBytes, _, _) ::& rs) =-  pure $ i :/ SHA256 ::: ((STc SCBytes, NStar, vn) ::& rs)+  pure $ i :/ SHA256 ::: ((STc SCBytes, starNotes, vn) ::& rs)  typeCheckInstr (U.SHA512 vn)            i@((STc SCBytes, _, _) ::& rs) =-  pure $ i :/ SHA512 ::: ((STc SCBytes, NStar, vn) ::& rs)+  pure $ i :/ SHA512 ::: ((STc SCBytes, starNotes, vn) ::& rs)  typeCheckInstr (U.BLAKE2B vn)            i@((STc SCBytes, _, _) ::& rs) =-  pure $ i :/ BLAKE2B ::: ((STc SCBytes, NStar, vn) ::& rs)+  pure $ i :/ BLAKE2B ::: ((STc SCBytes, starNotes, vn) ::& rs)  typeCheckInstr (U.HASH_KEY vn)            i@((STKey, _, _) ::& rs) =-  pure $ i :/ HASH_KEY ::: ((STc SCKeyHash, NStar, vn) ::& rs)+  pure $ i :/ HASH_KEY ::: ((STc SCKeyHash, starNotes, vn) ::& rs)  typeCheckInstr (U.STEPS_TO_QUOTA vn) i =-  pure $ i :/ STEPS_TO_QUOTA ::: ((STc SCNat, NStar, vn) ::& i)+  pure $ i :/ STEPS_TO_QUOTA ::: ((STc SCNat, starNotes, vn) ::& i)  typeCheckInstr (U.SOURCE vn) i =-  pure $ i :/ SOURCE ::: ((STc SCAddress, NStar, vn) ::& i)+  pure $ i :/ SOURCE ::: ((STc SCAddress, starNotes, vn) ::& i)  typeCheckInstr (U.SENDER vn) i =-  pure $ i :/ SENDER ::: ((STc SCAddress, NStar, vn) ::& i)+  pure $ i :/ SENDER ::: ((STc SCAddress, starNotes, vn) ::& i)  typeCheckInstr (U.ADDRESS vn) i@((STContract _, _, _) ::& rs) =-  pure $ i :/ ADDRESS ::: ((STc SCAddress, NStar, vn) ::& rs)+  pure $ i :/ ADDRESS ::: ((STc SCAddress, starNotes, vn) ::& rs) +typeCheckInstr (U.CHAIN_ID vn) i =+  pure $ i :/ CHAIN_ID ::: ((STChainId, starNotes, vn) ::& i)+ typeCheckInstr instr sit = typeCheckInstrErr instr (SomeHST sit) "unknown expression"  -- | Helper function for two-branch if where each branch is given a single@@ -759,7 +915,7 @@   when (any hasSelf is) $     typeCheckInstrErr instr (SomeHST i) "The SELF instruction cannot appear in a lambda"   _ :/ lamI <- lift $ typeCheckList is ((it, ins, def) ::& SNil)-  let lamNotes onsr = mkNotes $ NTLambda def ins onsr+  let lamNotes onsr = NTLambda def ins onsr   let lamSt onsr = (STLambda it ot, lamNotes onsr, vn) ::& i   fmap (i :/) $ case lamI of     lam ::: lo -> do@@ -767,11 +923,11 @@         Right Refl -> do             let (_, ons', _) ::& SNil = lo             onsr <- onTypeCheckInstrAnnErr instr i "wrong output type of lambda's expression:" (converge ons ons')-            pure (LAMBDA (VLam lam) ::: lamSt onsr)+            pure (LAMBDA (VLam $ RfNormal lam) ::: lamSt onsr)         Left m -> onTypeCheckInstrErr instr (SomeHST i)                     "wrong output type of lambda's expression:" (Left m)     AnyOutInstr lam ->-      pure (LAMBDA (VLam lam) ::: lamSt ons)+      pure (LAMBDA (VLam $ RfAlwaysFails lam) ::: lamSt ons)   where     hasSelf :: U.ExpandedOp -> Bool     hasSelf = everything (||)@@ -781,3 +937,35 @@            _ -> False        )       )++----------------------------------------------------------------------------+-- Helpers for DIP (n) typechecking+----------------------------------------------------------------------------++-- Helper data type we use to typecheck DIPN.+data TCDipHelper inp where+  TCDipHelper ::+    forall (n :: Peano) inp out s s'.+    (Typeable out, ConstraintDIPN n inp out s s') =>+    Sing n -> Instr s s' -> HST out -> TCDipHelper inp++typeCheckDipBody ::+     forall inp r. Typeable inp+  => U.ExpandedInstr+  -> [U.ExpandedOp]+  -> HST inp+  -> (forall out. Typeable out =>+                    Instr inp out -> HST out -> TypeCheckInstr r)+  -> TypeCheckInstr r+typeCheckDipBody mainInstr instructions inputHST callback = do+  _ :/ tp <- lift (typeCheckList instructions inputHST)+  case tp of+    AnyOutInstr _ ->+      -- This may seem like we throw error because of despair, but in fact,+      -- the reference implementation seems to behave exactly in this way -+      -- if output stack of code block within @DIP@ occurs to be any, an+      -- error "FAILWITH must be at tail position" is raised.+      -- It is not allowed even in `DIP 0`.+      typeCheckInstrErr mainInstr (SomeHST inputHST)+          "Code within DIP instruction always fails, which is not allowed"+    subI ::: t -> callback subI t
src/Michelson/TypeCheck/TypeCheck.hs view
@@ -6,7 +6,8 @@   , TypeCheck   , runTypeCheck   , TypeCheckInstr-  , runTypeCheckTest+  , runTypeCheckIsolated+  , mapTCError    , tcContractParamL   , tcContractsL@@ -14,19 +15,21 @@   ) where  import Control.Lens (makeLensesWith)+import Control.Monad.Except (withExceptT)+import Control.Monad.Reader (mapReaderT)  import Michelson.ErrorPos (InstrCallStack) import Michelson.TypeCheck.Error (TCError) import Michelson.TypeCheck.Types import qualified Michelson.Untyped as U-import Tezos.Address (Address)+import Tezos.Address (ContractHash) import Util.Lens  type TypeCheck a =   ExceptT TCError     (State TypeCheckEnv) a -type TcOriginatedContracts = Map Address U.Type+type TcOriginatedContracts = Map ContractHash U.Type  -- | The typechecking state data TypeCheckEnv = TypeCheckEnv@@ -44,9 +47,13 @@ -- | Run type checker as if it worked isolated from other world - -- no access to environment of the current contract is allowed. ----- Use this function for test purposes only.-runTypeCheckTest :: TypeCheck a -> Either TCError a-runTypeCheckTest = evaluatingState initSt . runExceptT+-- Use this function for test purposes only or for some utilities when+-- environment does not matter. In particular, it is assumed that+-- whatever we typecheck does not depend on the parameter type of the+-- contract which is being typechecked (because there is no contract+-- that we are typechecking).+runTypeCheckIsolated :: TypeCheck a -> Either TCError a+runTypeCheckIsolated = evaluatingState initSt . runExceptT   where   initSt =     TypeCheckEnv@@ -59,6 +66,10 @@  type TypeCheckInstr a =        ReaderT InstrCallStack (ExceptT TCError (State TypeCheckEnv)) a++-- | Run 'TypeCheckInstr' and modify thrown errors using given functions.+mapTCError :: (TCError -> TCError) -> TypeCheckInstr a -> TypeCheckInstr a+mapTCError f = mapReaderT (withExceptT f)  -- pva701: it's really painful to add arguments to TcInstrHandler -- due to necessity to refactor @typeCheckInstr@.
src/Michelson/TypeCheck/Types.hs view
@@ -4,11 +4,13 @@     , SomeHST (..)     , SomeInstrOut (..)     , SomeInstr (..)-    , SomeValue (..)+    , SomeNotedValue (..)     , SomeContract (..)     , SomeCValue (..)+    , StorageOrParameter (..)     , BoundVars (..)     , TcExtFrames+    , mapSomeContract     , noBoundVars     ) where @@ -17,15 +19,14 @@ import qualified Text.Show import qualified Data.Map.Lazy as Map -import Michelson.EqParam (eqParam1) import Michelson.Untyped (Var, Type, noAnn)+import Michelson.Untyped.Annotation (VarAnn) import Michelson.Typed-  (HasNoBigMap, HasNoOp, Notes(..), Sing(..), BigMapConstraint, T(..), fromSingT)+  (Notes(..), Sing(..), T(..), fromSingT, starNotes) import qualified Michelson.Typed as T import Michelson.Typed.Instr import Michelson.Typed.Value--import Michelson.Untyped.Annotation (VarAnn)+import Util.Typeable  -- | Data type holding type information for stack (Heterogeneous Stack Type). --@@ -82,7 +83,7 @@   => Sing x   -> HST xs   -> HST (x ': xs)-s -:& hst = (s, NStar, noAnn) ::& hst+s -:& hst = (s, starNotes, noAnn) ::& hst infixr 7 -:&  -- | No-argument type wrapper for @HST@ data type.@@ -134,12 +135,17 @@  -- | Data type, holding strictly-typed Michelson value along with its -- type singleton.-data SomeValue where+data SomeNotedValue where     (::::) :: (SingI t, Typeable t)            => T.Value t            -> (Sing t, Notes t)-           -> SomeValue+           -> SomeNotedValue +instance Show SomeNotedValue where+  show (val :::: (sing, notes)) =+    show val <> " :: " <> "(" <> show (fromSingT sing)+    <> ", " <> show notes <> ")"+ -- | Data type, holding strictly-typed Michelson value along with its -- type singleton. data SomeCValue where@@ -147,14 +153,14 @@            => CValue t -> Sing t -> SomeCValue  data SomeContract where-  SomeContract-    :: (Each [Typeable, SingI, HasNoOp] [st, cp]-       , HasNoBigMap cp, BigMapConstraint st)-    => Contract cp st-    -> HST (ContractInp cp st)-    -> HST (ContractOut st)-    -> SomeContract+  SomeContract :: FullContract cp st -> SomeContract +mapSomeContract ::+  (forall inp out. Instr inp out -> Instr inp out)+  -> SomeContract+  -> SomeContract+mapSomeContract f (SomeContract fc) = SomeContract $ mapFullContractCode f fc+ deriving instance Show SomeContract  -- | Set of variables defined in a let-block.@@ -165,3 +171,7 @@  -- | State for type checking @nop@ type TcExtFrames = [BoundVars]++-- | Datatype used in `typeCheckStorageOrParameter` instead of simple `Bool`+-- for more convenience.+data StorageOrParameter = Storage | Parameter deriving Eq
src/Michelson/TypeCheck/Value.hs view
@@ -4,6 +4,7 @@     ) where  import Control.Monad.Except (liftEither, throwError)+import Data.Constraint (Dict(..)) import Data.Default (def) import qualified Data.Map as M import qualified Data.Set as S@@ -18,12 +19,11 @@ import Michelson.TypeCheck.TypeCheck (TcInstrHandler, TypeCheckEnv(..), TypeCheckInstr) import Michelson.TypeCheck.Types import Michelson.Typed-  (CT(..), CValue(..), Notes(..), Notes'(..), Sing(..), Value'(..), converge, fromSingCT,-  fromSingT, mkNotes, notesCase)+  (CT(..), CValue(..), Notes(..), Sing(..), Value'(..), converge, fromSingCT, fromSingT, starNotes) import qualified Michelson.Typed as T import qualified Michelson.Untyped as U import Tezos.Address (Address(..), parseAddress)-import Tezos.Core (mkMutez, parseTimestamp, timestampFromSeconds)+import Tezos.Core import Tezos.Crypto (parseKeyHash, parsePublicKey, parseSignature)  typeCheckCValue@@ -31,16 +31,21 @@ typeCheckCValue (U.ValueInt i) CInt = pure $ CvInt i :--: SCInt typeCheckCValue (U.ValueInt i) CNat   | i >= 0 = pure $ CvNat (fromInteger i) :--: SCNat-typeCheckCValue (U.ValueInt (mkMutez . fromInteger -> Just mtz)) CMutez =+  | otherwise = Left (U.ValueInt i, NegativeNat)+typeCheckCValue v@(U.ValueInt i) CMutez = do+  mtz <- maybeToRight (v, InvalidTimestamp) . mkMutez $ fromInteger i   pure $ CvMutez mtz :--: SCMutez typeCheckCValue (U.ValueString s) CString =   pure $ CvString s :--: SCString-typeCheckCValue (U.ValueString (parseAddress . unMText -> Right s)) CAddress =-  pure $ CvAddress s :--: SCAddress-typeCheckCValue (U.ValueString (parseKeyHash . unMText -> Right s)) CKeyHash =-  pure $ CvKeyHash s :--: SCKeyHash-typeCheckCValue (U.ValueString (parseTimestamp . unMText -> Just t)) CTimestamp =-  pure $ CvTimestamp t :--: SCTimestamp+typeCheckCValue v@(U.ValueString s) CAddress = do+  addr <- T.parseEpAddress (unMText s) `onLeft` ((v, ) . InvalidAddress)+  pure $ CvAddress addr :--: SCAddress+typeCheckCValue v@(U.ValueString s) CKeyHash = do+  kHash <- parseKeyHash (unMText s) `onLeft` ((v, ) . InvalidKeyHash)+  pure $ CvKeyHash kHash :--: SCKeyHash+typeCheckCValue v@(U.ValueString s) CTimestamp = do+  tstamp <- maybeToRight (v, InvalidTimestamp) . parseTimestamp $ unMText s+  pure $ CvTimestamp tstamp :--: SCTimestamp typeCheckCValue (U.ValueInt i) CTimestamp =   pure $ CvTimestamp (timestampFromSeconds i) :--: SCTimestamp typeCheckCValue (U.ValueBytes (U.InternalByteString s)) CBytes =@@ -48,7 +53,7 @@ typeCheckCValue U.ValueTrue CBool = pure $ CvBool True :--: SCBool typeCheckCValue U.ValueFalse CBool = pure $ CvBool False :--: SCBool typeCheckCValue v t =-  Left $ (v, UnknownType (T.Tc t))+  Left $ (v, InvalidValueType (T.Tc t))  typeCheckCVals   :: forall t op . (Typeable t, SingI t)@@ -83,69 +88,83 @@   :: TcInstrHandler   -> U.Value   -> (Sing t, Notes t)-  -> TypeCheckInstr SomeValue-typeCheckValImpl _ mv (t@(STc ct), ann) = do-  let nt = notesCase U.noAnn (\(NTc x) -> x) ann+  -> TypeCheckInstr SomeNotedValue+typeCheckValImpl _ mv (t@(STc ct), NTc nt) = do   case typeCheckCValue mv (fromSingCT ct) of     Left (uval, err) -> tcFailedOnValue uval (fromSingT $ t) "" (Just err)-    Right (v :--: cst) -> pure $ VC v :::: (STc cst, mkNotes $ NTc nt)+    Right (v :--: cst) -> pure $ VC v :::: (STc cst, NTc nt) typeCheckValImpl _ (U.ValueString (parsePublicKey . unMText -> Right s)) t@(STKey, _) =   pure $ T.VKey s :::: t  typeCheckValImpl _ (U.ValueString (parseSignature . unMText -> Right s)) t@(STSignature, _) =   pure $ VSignature s :::: t -typeCheckValImpl _ (U.ValueString (parseAddress . unMText -> Right s@(KeyAddress _)))-                   t@(STContract STUnit, _) =-    pure $ T.VContract s :::: t+typeCheckValImpl _ (U.ValueString (parseChainId . unMText -> Right ci)) t@(STChainId, _) =+  pure $ VChainId ci :::: t+typeCheckValImpl _ (U.ValueBytes (mkChainId . U.unInternalByteString -> Just ci)) t@(STChainId, _) =+  pure $ VChainId ci :::: t -typeCheckValImpl _ cv@(U.ValueString (parseAddress . unMText -> Right s))+typeCheckValImpl _ cv@(U.ValueString (parseAddress . unMText -> Right addr))                    t@(STContract pc, cn) = do   instrPos <- ask   let tcFail = \msg -> TCFailedOnValue cv (fromSingT $ fst t) msg instrPos Nothing-  let pn = notesCase NStar (\(NTContract _ x) -> x) cn+  let NTContract _ pn = cn   contracts <- gets tcContracts-  case M.lookup s contracts of-    Just contractParam -> do-      liftEither $ first (TCFailedOnValue cv (fromSingT $ fst t) "invalid contract parameter" instrPos . Just) $-        compareTypes (pc, pn) contractParam-      pure $ VContract s :::: t-    _ -> throwError $ tcFail $ "Contract literal " <> pretty s <> " doesn't exist"+  let ensureTypeMatches cp =+        liftEither $+        first (TCFailedOnValue cv (fromSingT $ fst t) "invalid contract parameter" instrPos . Just) $+          compareTypes (pc, pn) cp+  -- TODO [TM-280]: Actually the desired entrypoint can be specified in+  -- "<address>%<entrypoint>" format. Support this scenario.+  let unsupportedType :: Text -> Either TCError a+      unsupportedType desc =+        Left $+        TCFailedOnValue cv (fromSingT pc) (desc <> " in type argument of 'contract' type") instrPos $+        Just (UnsupportedTypes [fromSingT pc])+  Dict <- liftEither $ maybe (unsupportedType "Operation") pure (T.opAbsense pc)+  Dict <- liftEither $ maybe (unsupportedType "Nested BigMaps") pure (T.nestedBigMapsAbsense pc)+  let entrypoint = def+  case addr of+    KeyAddress _ -> do+      ensureTypeMatches U.tyImplicitAccountParam+      pure $ VContract addr entrypoint :::: t+    ContractAddress ca ->+      case M.lookup ca contracts of+        Just contractParam -> do+          ensureTypeMatches contractParam+          pure $ VContract addr entrypoint :::: t+        _ -> throwError $ tcFail $ "Contract literal " <> pretty addr <> " doesn't exist"  typeCheckValImpl _ U.ValueUnit t@(STUnit, _) = pure $ VUnit :::: t-typeCheckValImpl tcDo (U.ValuePair ml mr) (STPair lt rt, pn) = do-  let (n1, n2, n3, nl, nr) =-        notesCase (U.noAnn, U.noAnn, U.noAnn, NStar, NStar) (\(NTPair x1 x2 x3 xl xr) -> (x1, x2, x3, xl, xr)) pn+typeCheckValImpl+  tcDo+  (U.ValuePair ml mr)+  (STPair lt rt, NTPair n1 n2 n3 nl nr)+    = do   l :::: (lst, ln) <- typeCheckValImpl tcDo ml (lt, nl)   r :::: (rst, rn) <- typeCheckValImpl tcDo mr (rt, nr)-  let ns = mkNotes $ NTPair n1 n2 n3 ln rn-  pure $ VPair (l, r) :::: (STPair lst rst, ns)-typeCheckValImpl tcDo (U.ValueLeft ml) (STOr lt rt, ann) = do-  let (n1, n2, n3, nl, nr) =-        notesCase (U.noAnn, U.noAnn, U.noAnn, NStar, NStar) (\(NTOr x1 x2 x3 xl xr) -> (x1, x2, x3, xl, xr)) ann+  pure $ VPair (l, r) :::: (STPair lst rst, NTPair n1 n2 n3 ln rn)+typeCheckValImpl tcDo (U.ValueLeft ml) (STOr lt rt, NTOr n1 n2 n3 nl nr) = do   l :::: (lst, ln) <- typeCheckValImpl tcDo ml (lt, nl)-  pure $ VOr (Left l) :::: ( STOr lst rt-                            , mkNotes $ NTOr n1 n2 n3 ln nr )-typeCheckValImpl tcDo (U.ValueRight mr) (STOr lt rt, ann) = do-  let (n1, n2, n3, nl, nr) =-        notesCase (U.noAnn, U.noAnn, U.noAnn, NStar, NStar) (\(NTOr x1 x2 x3 xl xr) -> (x1, x2, x3, xl, xr)) ann+  pure $ VOr (Left l) :::: ( STOr lst rt, NTOr n1 n2 n3 ln nr)+typeCheckValImpl tcDo (U.ValueRight mr) (STOr lt rt, NTOr n1 n2 n3 nl nr) = do   r :::: (rst, rn) <- typeCheckValImpl tcDo mr (rt, nr)-  pure $ VOr (Right r) :::: ( STOr lt rst-                            , mkNotes $ NTOr n1 n2 n3 nl rn )-typeCheckValImpl tcDo (U.ValueSome mv) (STOption vt, ann) = do-  let (n1, n2, nt) = notesCase (U.noAnn, U.noAnn, NStar) (\(NTOption x1 x2 xt) -> (x1, x2, xt)) ann+  pure $ VOr (Right r) :::: ( STOr lt rst, NTOr n1 n2 n3 nl rn)+typeCheckValImpl tcDo (U.ValueSome mv) (STOption vt, NTOption na nt) = do   v :::: (vst, vns) <- typeCheckValImpl tcDo mv (vt, nt)-  let ns = mkNotes $ NTOption n1 n2 vns-  pure $ VOption (Just v) :::: (STOption vst, ns)+  pure $ VOption (Just v) :::: (STOption vst, NTOption na vns) typeCheckValImpl _ U.ValueNone t@(STOption _, _) =   pure $ VOption Nothing :::: t  typeCheckValImpl _ U.ValueNil t@(STList _, _) =   pure $ T.VList [] :::: t -typeCheckValImpl tcDo (U.ValueSeq (toList -> mels)) t@(STList vt, ann) = do-  let nt = notesCase NStar (\(NTList _ x) -> x) ann-  (els, _) <- typeCheckValsImpl tcDo mels (vt, nt)+typeCheckValImpl+  tcDo+  (U.ValueSeq (toList -> mels))+  t@(STList vt, NTList _ x)+    = do+  (els, _) <- typeCheckValsImpl tcDo mels (vt, x)   pure $ VList els :::: t  typeCheckValImpl _ U.ValueNil t@(STSet _, _) = pure $ T.VSet S.empty :::: t@@ -161,40 +180,49 @@  typeCheckValImpl _ U.ValueNil t@(STMap _ _, _) = pure $ T.VMap M.empty :::: t -typeCheckValImpl tcDo sq@(U.ValueMap (toList -> mels)) t@(STMap kt vt, ann) = do-  let vn = notesCase NStar (\(NTMap _ _ nt) -> nt) ann+typeCheckValImpl+  tcDo+  sq@(U.ValueMap (toList -> mels))+  t@(STMap kt vt, NTMap _ _ vn)+    = do   keyOrderedElts <- typeCheckMapVal tcDo mels sq vn kt vt   pure $ VMap (M.fromDistinctAscList keyOrderedElts) :::: t  typeCheckValImpl _ U.ValueNil t@(STBigMap _ _ , _) = pure $ T.VBigMap M.empty :::: t -typeCheckValImpl tcDo sq@(U.ValueMap (toList -> mels)) t@(STBigMap kt vt, ann) = do-  let vn = notesCase NStar (\(NTBigMap _ _ nt) -> nt) ann+typeCheckValImpl+  tcDo+  sq@(U.ValueMap (toList -> mels))+  t@(STBigMap kt vt, NTBigMap _ _ vn)+    = do   keyOrderedElts <- typeCheckMapVal tcDo mels sq vn kt vt   pure $ VBigMap (M.fromDistinctAscList keyOrderedElts) :::: t -typeCheckValImpl tcDo v (t@(STLambda (it :: Sing it) (ot :: Sing ot)), ann) = do+typeCheckValImpl+  tcDo+  v+  ( t@(STLambda (it :: Sing it) (ot :: Sing ot))+  , NTLambda vn _ _+  )+    = do   mp <- case v of     U.ValueNil       -> pure []     U.ValueLambda mp -> pure $ toList mp     _ -> tcFailedOnValue v (fromSingT t) "unexpected value" Nothing-  let vn = notesCase U.noAnn (\(NTLambda n1 _ _) -> n1) ann-  li :/ instr <- typeCheckImpl tcDo mp ((it, NStar, def) ::& SNil)+  li :/ instr <- typeCheckImpl tcDo mp ((it, starNotes, def) ::& SNil)   let (_, ins, _) ::& SNil = li   let lamS = STLambda it ot-  let lamN ons = mkNotes $ NTLambda def ins ons   case instr of     lam ::: (lo :: HST lo) -> do       case eqHST1 @ot lo of         Right Refl -> do           let (_, ons, _) ::& SNil = lo-          let ns = mkNotes $ NTLambda vn ins ons-          pure $ VLam lam :::: (STLambda it ot, ns)+          pure $ VLam (T.RfNormal lam) :::: (STLambda it ot, NTLambda vn ins ons)         Left m ->           tcFailedOnValue v (fromSingT t)                   "wrong output type of lambda's value:" (Just m)     AnyOutInstr lam ->-      pure $ VLam lam :::: (lamS, lamN NStar)+      pure $ VLam (T.RfAlwaysFails lam) :::: (lamS, NTLambda def ins starNotes)  typeCheckValImpl _ v (t, _) = tcFailedOnValue v (fromSingT t) "unknown value" Nothing 
src/Michelson/Typed.hs view
@@ -7,12 +7,14 @@ import Michelson.Typed.Arith as Exports import Michelson.Typed.Convert as Exports import Michelson.Typed.CValue as Exports+import Michelson.Typed.Doc as Exports+import Michelson.Typed.EntryPoints as Exports import Michelson.Typed.Extract as Exports import Michelson.Typed.Haskell as Exports import Michelson.Typed.Instr as Exports import Michelson.Typed.Polymorphic as Exports-import Michelson.Typed.Print as Exports import Michelson.Typed.Scope as Exports import Michelson.Typed.Sing as Exports import Michelson.Typed.T as Exports+import Michelson.Typed.Util as Exports import Michelson.Typed.Value as Exports
src/Michelson/Typed/Aliases.hs view
@@ -1,5 +1,7 @@ module Michelson.Typed.Aliases   ( Value+  , SomeValue+  , SomeConstrainedValue   , Operation   ) where @@ -7,4 +9,6 @@ import Michelson.Typed.Value  type Value = Value' Instr+type SomeValue = SomeValue' Instr+type SomeConstrainedValue = SomeConstrainedValue' Instr type Operation = Operation' Instr
src/Michelson/Typed/Annotation.hs view
@@ -16,157 +16,111 @@  module Michelson.Typed.Annotation   ( Notes (..)-  , Notes' (..)   , AnnConvergeError(..)   , converge   , convergeAnns-  , notesCase-  , isStar-  , mkNotes   , orAnn+  , isStar+  , starNotes   ) where  import Data.Default (Default(..)) import qualified Data.Kind as Kind+import Data.Singletons (SingI(..)) import Fmt (Buildable(..), (+|), (|+)) -import Michelson.EqParam import Michelson.Typed.T (T(..))-import Michelson.Untyped.Annotation (Annotation, FieldAnn, TypeAnn, unifyAnn)---- | Data type, holding annotation data for a given Michelson type @t@--- or @*@ in case no data is provided for the tree.------ There is a little semantical duplication between data type constructors.--- Semantics behind 'NStar' constructor are exactly same as semantics behind--- 'N' constructor with relevant 'Notes'' constructor be given all default--- values (which means all annotations are empty).------ Constructor 'NStar' is given as a tiny optimization to allow handling--- no-annotation case completely for free (see 'converge' and 'mkNotes'--- functions).-data Notes t = N (Notes' t) | NStar-  deriving (Eq)--deriving instance Show (Notes p)---- | Helper function for work with 'Notes' data type.------ @---  notesCase f g notes--- @------ is equivalent to------ @---  case notes of---    NStar -> f---    N v -> g v--- @----notesCase :: r -> (Notes' t -> r) -> Notes t -> r-notesCase a _ NStar = a-notesCase _ f (N b) = f b+import Michelson.Typed.Sing+import Michelson.Untyped.Annotation (Annotation, FieldAnn, TypeAnn, unifyAnn, noAnn)+import Util.Typeable  -- | Data type, holding annotation data for a given Michelson type @t@. -- -- Each constructor corresponds to exactly one constructor of 'T' -- and holds all type and field annotations that can be attributed to a -- Michelson type corrspoding to @t@.-data Notes' t where-  NTc         :: TypeAnn -> Notes' ('Tc ct)-  NTKey       :: TypeAnn -> Notes' 'TKey-  NTUnit      :: TypeAnn -> Notes' 'TUnit-  NTSignature :: TypeAnn -> Notes' 'TSignature-  NTOption    :: TypeAnn -> FieldAnn -> Notes t -> Notes' ('TOption t)-  NTList      :: TypeAnn -> Notes t -> Notes' ('TList t)-  NTSet       :: TypeAnn -> TypeAnn -> Notes' ('TSet ct)-  NTOperation :: TypeAnn -> Notes' 'TOperation-  NTContract  :: TypeAnn -> Notes t -> Notes' ('TContract t)+data Notes t where+  NTc         :: TypeAnn -> Notes ('Tc ct)+  NTKey       :: TypeAnn -> Notes 'TKey+  NTUnit      :: TypeAnn -> Notes 'TUnit+  NTSignature :: TypeAnn -> Notes 'TSignature+  NTChainId   :: TypeAnn -> Notes 'TChainId+  NTOption    :: TypeAnn -> Notes t -> Notes ('TOption t)+  NTList      :: TypeAnn -> Notes t -> Notes ('TList t)+  NTSet       :: TypeAnn -> TypeAnn -> Notes ('TSet ct)+  NTOperation :: TypeAnn -> Notes 'TOperation+  NTContract  :: TypeAnn -> Notes t -> Notes ('TContract t)   NTPair      :: TypeAnn -> FieldAnn -> FieldAnn-               -> Notes p -> Notes q -> Notes' ('TPair p q)+              -> Notes p -> Notes q -> Notes ('TPair p q)   NTOr        :: TypeAnn -> FieldAnn -> FieldAnn-               -> Notes p -> Notes q -> Notes' ('TOr p q)-  NTLambda    :: TypeAnn -> Notes p -> Notes q -> Notes' ('TLambda p q)-  NTMap       :: TypeAnn -> TypeAnn -> Notes v -> Notes' ('TMap k v)-  NTBigMap   :: TypeAnn -> TypeAnn -> Notes v -> Notes' ('TBigMap k v)--deriving instance Show (Notes' t)-deriving instance Eq (Notes' t)+              -> Notes p -> Notes q -> Notes ('TOr p q)+  NTLambda    :: TypeAnn -> Notes p -> Notes q -> Notes ('TLambda p q)+  NTMap       :: TypeAnn -> TypeAnn -> Notes v -> Notes ('TMap k v)+  NTBigMap    :: TypeAnn -> TypeAnn -> Notes v -> Notes ('TBigMap k v) --- | Check whether given annotations object is @*@.-isStar :: Notes t -> Bool-isStar NStar = True-isStar _ = False+deriving instance Show (Notes t)+deriving instance Eq (Notes t) -isDef :: (Eq t, Default t) => t -> Bool-isDef = (== def)+-- | In memory of `NStar` constructor.+--   Generates notes with no annotations.+starNotes :: forall t. SingI t => Notes t+starNotes = case sing @t of+  STc _ -> NTc noAnn+  STKey -> NTKey noAnn+  STUnit -> NTUnit noAnn+  STSignature -> NTSignature noAnn+  STChainId -> NTChainId noAnn+  STOperation -> NTOperation noAnn+  STSet _ -> NTSet noAnn noAnn+  STList _ -> NTList noAnn starNotes+  STOption _ -> NTOption noAnn starNotes+  STContract _ -> NTContract noAnn starNotes+  STMap _ _ -> NTMap noAnn noAnn starNotes+  STBigMap _ _ -> NTBigMap noAnn noAnn starNotes+  STPair _ _ -> NTPair noAnn noAnn noAnn starNotes starNotes+  STOr _ _ -> NTOr noAnn noAnn noAnn starNotes starNotes+  STLambda _ _ -> NTLambda noAnn starNotes starNotes --- | Checks whether given notes @n@ can be immediately converted to star--- and returns either @NStar@ or @N n@.------ Given @n :: Notes' t@ can be immediately converted to star iff all nested--- @(sn :: Notes t) == NStar@ and for each annotation @an@: @an == def@.-mkNotes :: Notes' t -> Notes t-mkNotes (NTOption tn fn ns) | isStar ns && isDef tn && isDef fn   = NStar-mkNotes (NTList tn ns)      | isStar ns && isDef tn               = NStar-mkNotes (NTSet tn en)       | isDef tn && isDef en                = NStar-mkNotes (NTContract tn ns)  | isStar ns && isDef tn               = NStar-mkNotes (NTPair tn fn1 fn2 ns1 ns2)-  | isStar ns1 && isStar ns2 && isDef tn && isDef fn1 && isDef fn2 = NStar-mkNotes (NTOr tn fn1 fn2 ns1 ns2)-  | isStar ns1 && isStar ns2 && isDef tn && isDef fn1 && isDef fn2 = NStar-mkNotes (NTLambda tn ns1 ns2)-  | isStar ns1 && isStar ns2 && isDef tn                           = NStar-mkNotes (NTMap tn kn vns)-  | isStar vns && isDef tn && isDef kn                             = NStar-mkNotes (NTc t) | isDef t                                         = NStar-mkNotes (NTKey t) | isDef t                                       = NStar-mkNotes (NTUnit t) | isDef t                                      = NStar-mkNotes (NTSignature t) | isDef t                                 = NStar-mkNotes (NTOperation t) | isDef t                                 = NStar-mkNotes n = N n+-- | Checks if no annotations are present.+isStar :: SingI t => Notes t -> Bool+isStar = (== starNotes)  orAnn :: Annotation t -> Annotation t -> Annotation t orAnn a b = bool a b (a == def)  -- | Combines two annotations trees `a` and `b` into a new one `c` -- in such a way that `c` can be obtained from both `a` and `b` by replacing--- some @*@ leafs with type or/and field annotations.-converge' :: Notes' t -> Notes' t -> Either AnnConvergeError (Notes' t)-converge' (NTc a) (NTc b) = NTc <$> convergeAnns a b-converge' (NTKey a) (NTKey b) = NTKey <$> convergeAnns a b-converge' (NTUnit a) (NTUnit b) = NTUnit <$> convergeAnns a b-converge' (NTSignature a) (NTSignature b) =+-- some empty leaves with type or/and field annotations.+converge :: Notes t -> Notes t -> Either AnnConvergeError (Notes t)+converge (NTc a) (NTc b) = NTc <$> convergeAnns a b+converge (NTKey a) (NTKey b) = NTKey <$> convergeAnns a b+converge (NTUnit a) (NTUnit b) = NTUnit <$> convergeAnns a b+converge (NTSignature a) (NTSignature b) =     NTSignature <$> convergeAnns a b-converge' (NTOption a f n) (NTOption b g m) =-  NTOption <$> convergeAnns a b <*> convergeAnns f g <*> converge n m-converge' (NTList a n) (NTList b m) =+converge (NTChainId a) (NTChainId b) =+    NTChainId <$> convergeAnns a b+converge (NTOption a n) (NTOption b m) =+  NTOption <$> convergeAnns a b <*> converge n m+converge (NTList a n) (NTList b m) =   NTList <$> convergeAnns a b <*> converge n m-converge' (NTSet a n) (NTSet b m) =+converge (NTSet a n) (NTSet b m) =   NTSet <$> convergeAnns a b <*> convergeAnns n m-converge' (NTOperation a) (NTOperation b) =+converge (NTOperation a) (NTOperation b) =   NTOperation <$> convergeAnns a b-converge' (NTContract a n) (NTContract b m) =+converge (NTContract a n) (NTContract b m) =   NTContract <$> convergeAnns a b <*> converge n m-converge' (NTPair a pF qF pN qN) (NTPair b pG qG pM qM) =+converge (NTPair a pF qF pN qN) (NTPair b pG qG pM qM) =   NTPair <$> convergeAnns a b <*> convergeAnns pF pG           <*> convergeAnns qF qG <*> converge pN pM <*> converge qN qM-converge' (NTOr a pF qF pN qN) (NTOr b pG qG pM qM) =+converge (NTOr a pF qF pN qN) (NTOr b pG qG pM qM) =   NTOr <$> convergeAnns a b <*> convergeAnns pF pG <*> convergeAnns qF qG           <*> converge pN pM <*> converge qN qM-converge' (NTLambda a pN qN) (NTLambda b pM qM) =+converge (NTLambda a pN qN) (NTLambda b pM qM) =   NTLambda <$> convergeAnns a b <*> converge pN pM <*> converge qN qM-converge' (NTMap a kN vN) (NTMap b kM vM) =+converge (NTMap a kN vN) (NTMap b kM vM) =   NTMap <$> convergeAnns a b <*> convergeAnns kN kM <*> converge vN vM-converge' (NTBigMap a kN vN) (NTBigMap b kM vM) =+converge (NTBigMap a kN vN) (NTBigMap b kM vM) =   NTBigMap <$> convergeAnns a b <*> convergeAnns kN kM <*> converge vN vM---- | Same as 'converge'' but works with 'Notes' data type.-converge :: Notes t -> Notes t -> Either AnnConvergeError (Notes t)-converge NStar a = pure a-converge a NStar = pure a-converge (N a) (N b) = N <$> converge' a b  data AnnConvergeError where   AnnConvergeError
src/Michelson/Typed/Arith.hs view
@@ -8,6 +8,7 @@   , UnaryArithOp (..)   , ArithError (..)   , ArithErrorType (..)+  , CompareOp (..)   , Add   , Sub   , Mul@@ -52,6 +53,11 @@   -- | Evaluate arithmetic operation on given operands.   evalOp :: proxy aop -> CValue n -> CValue m -> Either (ArithError (CValue n) (CValue m)) (CValue (ArithRes aop n m)) +-- | Class for comparison operations, special case of 'ArithOp'.+class CompareOp n where+  -- | Evaluate compare operation.+  compareOp :: CValue n -> CValue n -> Integer+ -- | Denotes the error type occured in the arithmetic operation. data ArithErrorType   = AddOverflow@@ -227,42 +233,36 @@   type UnaryArithRes Not 'CBool = 'CBool   evalUnaryArithOp _ (CvBool i) = CvBool (not i) -instance ArithOp Compare 'CBool 'CBool where-  type ArithRes Compare 'CBool 'CBool = 'CInt-  evalOp _ (CvBool i) (CvBool j) =-    Right $ CvInt $ toInteger $ fromEnum (compare i j) - 1-instance ArithOp Compare 'CAddress 'CAddress where-  type ArithRes Compare 'CAddress 'CAddress = 'CInt-  evalOp _ (CvAddress i) (CvAddress j) =-    Right $ CvInt $ toInteger $ fromEnum (compare i j) - 1-instance ArithOp Compare 'CNat 'CNat where-  type ArithRes Compare 'CNat 'CNat = 'CInt-  evalOp _ (CvNat i) (CvNat j) =-    Right $ CvInt $ toInteger $ fromEnum (compare i j) - 1-instance ArithOp Compare 'CInt 'CInt where-  type ArithRes Compare 'CInt 'CInt = 'CInt-  evalOp _ (CvInt i) (CvInt j) =-    Right $ CvInt $ toInteger $ fromEnum (compare i j) - 1-instance ArithOp Compare 'CString 'CString where-  type ArithRes Compare 'CString 'CString = 'CInt-  evalOp _ (CvString i) (CvString j) =-    Right $ CvInt $ toInteger $ fromEnum (compare i j) - 1-instance ArithOp Compare 'CBytes 'CBytes where-  type ArithRes Compare 'CBytes 'CBytes = 'CInt-  evalOp _ (CvBytes i) (CvBytes j) =-    Right $ CvInt $ toInteger $ fromEnum (compare i j) - 1-instance ArithOp Compare 'CTimestamp 'CTimestamp where-  type ArithRes Compare 'CTimestamp 'CTimestamp = 'CInt-  evalOp _ (CvTimestamp i) (CvTimestamp j) =-    Right $ CvInt $ toInteger $ fromEnum (compare i j) - 1-instance ArithOp Compare 'CMutez 'CMutez where-  type ArithRes Compare 'CMutez 'CMutez = 'CInt-  evalOp _ (CvMutez i) (CvMutez j) = Right $-    CvInt $ toInteger $ fromEnum (compare i j) - 1-instance ArithOp Compare 'CKeyHash 'CKeyHash where-  type ArithRes Compare 'CKeyHash 'CKeyHash = 'CInt-  evalOp _ (CvKeyHash i) (CvKeyHash j) =-    Right $ CvInt $ toInteger $ fromEnum (compare i j) - 1+instance (n ~ m, CompareOp n) => ArithOp Compare n m where+  type ArithRes Compare n m = 'CInt+  evalOp _ = Right . CvInt ... compareOp+instance CompareOp 'CBool where+  compareOp (CvBool i) (CvBool j) =+    toInteger $ fromEnum (compare i j) - 1+instance CompareOp 'CAddress where+  compareOp (CvAddress i) (CvAddress j) =+    toInteger $ fromEnum (compare i j) - 1+instance CompareOp 'CNat where+  compareOp (CvNat i) (CvNat j) =+    toInteger $ fromEnum (compare i j) - 1+instance CompareOp 'CInt where+  compareOp (CvInt i) (CvInt j) =+    toInteger $ fromEnum (compare i j) - 1+instance CompareOp 'CString where+  compareOp (CvString i) (CvString j) =+    toInteger $ fromEnum (compare i j) - 1+instance CompareOp 'CBytes where+  compareOp (CvBytes i) (CvBytes j) =+    toInteger $ fromEnum (compare i j) - 1+instance CompareOp 'CTimestamp where+  compareOp (CvTimestamp i) (CvTimestamp j) =+    toInteger $ fromEnum (compare i j) - 1+instance CompareOp 'CMutez where+  compareOp (CvMutez i) (CvMutez j) =+    toInteger $ fromEnum (compare i j) - 1+instance CompareOp 'CKeyHash where+  compareOp (CvKeyHash i) (CvKeyHash j) =+    toInteger $ fromEnum (compare i j) - 1  instance UnaryArithOp Eq' 'CInt where   type UnaryArithRes Eq' 'CInt = 'CBool
src/Michelson/Typed/CValue.hs view
@@ -6,8 +6,8 @@   ) where  import Michelson.Text+import Michelson.Typed.EntryPoints import Michelson.Typed.T (CT(..))-import Tezos.Address (Address) import Tezos.Core (Mutez, Timestamp) import Tezos.Crypto (KeyHash) @@ -29,7 +29,7 @@   CvBool      :: Bool -> CValue 'CBool   CvKeyHash   :: KeyHash -> CValue 'CKeyHash   CvTimestamp :: Timestamp -> CValue 'CTimestamp-  CvAddress   :: Address -> CValue 'CAddress+  CvAddress   :: EpAddress -> CValue 'CAddress  deriving instance Show (CValue t) deriving instance Eq (CValue t)
src/Michelson/Typed/Convert.hs view
@@ -2,6 +2,7 @@  module Michelson.Typed.Convert   ( convertContract+  , convertFullContract   , instrToOps   , untypeValue   ) where@@ -10,9 +11,10 @@ import Data.Singletons (SingI(sing)) import Fmt (pretty) -import Michelson.EqParam (eqParam1, eqParam2) import Michelson.Text+import Michelson.Typed.Annotation (Notes(..)) import Michelson.Typed.CValue+import Michelson.Typed.EntryPoints import Michelson.Typed.Extract (mkUType, toUType) import Michelson.Typed.Instr as Instr import Michelson.Typed.Scope@@ -20,10 +22,10 @@ import Michelson.Typed.T (CT(..), T(..)) import Michelson.Typed.Value import qualified Michelson.Untyped as U-import Tezos.Address (mformatAddress)-import Tezos.Core (unMutez)+import Tezos.Core (mformatChainId, unMutez) import Tezos.Crypto (mformatKeyHash, mformatPublicKey, mformatSignature) import Util.Peano+import Util.Typeable  convertContract   :: forall param store . (SingI param, SingI store)@@ -35,6 +37,17 @@     , code = instrToOps contract     } +addCtNote :: U.TypeAnn -> U.Comparable -> U.Comparable+addCtNote ta (U.Comparable ct _) = U.Comparable ct ta++convertFullContract+  :: forall param store . (SingI param, SingI store)+  => FullContract param store -> U.Contract+convertFullContract fc =+  let c = convertContract (fcCode fc)+  in c { U.para = mkUType sing (fcParamNotes fc)+       , U.stor = mkUType sing (fcStoreNotes fc) }+ -- | Convert a typed 'Val' to an untyped 'Value'. -- -- For full isomorphism type of the given 'Val' should not contain@@ -53,6 +66,8 @@     U.ValueUnit   (VSignature b, _) ->     U.ValueString $ mformatSignature b+  (VChainId b, _) ->+    U.ValueString $ mformatChainId b   (VOption (Just x), STOption _) ->     U.ValueSome (untypeValue x)   (VOption Nothing, STOption _) ->@@ -61,8 +76,8 @@     vList U.ValueSeq $ map untypeValue l   (VSet s, _) ->     vList U.ValueSeq $ map untypeCValue $ toList s-  (VContract b, _) ->-    U.ValueString $ mformatAddress b+  (VContract addr sepc, _) ->+    U.ValueString . mformatEpAddress $ EpAddress addr (sepcName sepc)    (VPair (l, r), STPair lt _) ->     case checkOpPresence lt of@@ -76,7 +91,7 @@     case checkOpPresence lt of       OpAbsent -> U.ValueRight (untypeValue x) -  (VLam (ops :: Instr '[inp] '[out]), _) ->+  (VLam (rfAnyInstr -> ops :: Instr '[inp] '[out]), _) ->     vList U.ValueLambda $ instrToOps ops    (VMap m, STMap _ vt) ->@@ -103,131 +118,257 @@   CvBool False -> U.ValueFalse   CvKeyHash h -> U.ValueString $ mformatKeyHash h   CvTimestamp t -> U.ValueString $ mkMTextUnsafe $ pretty t-  CvAddress a -> U.ValueString $ mformatAddress a+  CvAddress a -> U.ValueString $ mformatEpAddress a -instrToOps :: Instr inp out -> [U.ExpandedOp]+instrToOps :: HasCallStack => Instr inp out -> [U.ExpandedOp] instrToOps instr = case instr of+  Nop -> []   Seq i1 i2 -> instrToOps i1 <> instrToOps i2   Nested sq -> one $ U.SeqEx $ instrToOps sq-  i -> U.PrimEx <$> handleInstr i+  DocGroup _ sq -> instrToOps sq+  Ext (ext :: ExtInstr inp) -> (U.PrimEx . U.EXT) <$> extInstrToOps ext+  FrameInstr _ i -> instrToOps i+  InstrWithNotes n i -> case i of+    Nop -> instrToOps i+    Seq _ _ -> instrToOps i+    Nested _ -> instrToOps i+    DocGroup _ _ -> instrToOps i+    Ext _ -> instrToOps i+    InstrWithNotes _ _ -> instrToOps i+    -- For inner instruction, filter out values that we don't want to apply+    -- annotations to and delegate it's conversion to this function itself.+    -- If none of the above, convert a single instruction and copy annotations+    -- to it.+    _ -> [U.PrimEx $ handleInstrAnnotate i n]+  i -> [U.PrimEx $ handleInstr i]   -- TODO pva701: perphaps, typed instr has to hold a position too   -- to make it possible to report a precise location of a runtime error   where-    handleInstr :: Instr inp out -> [U.ExpandedInstr]+    handleInstrAnnotate+      :: forall inp' out' . HasCallStack+      => Instr inp' out' -> PackedNotes out' -> U.ExpandedInstr+    handleInstrAnnotate ins' (PackedNotes notes' sing') = let+      x = handleInstr ins' in addInstrNote x sing' notes'+      where+        addInstrNote+          :: HasCallStack+          => U.ExpandedInstr -> Sing t -> Notes t -> U.ExpandedInstr+        addInstrNote ins s nte = case (s, ins, nte) of+            (_, U.PUSH va _ v, _) -> U.PUSH va (mkUType s nte) v+            (_, U.SOME _ va, NTOption ta _) -> U.SOME ta va+            (STOption sp, U.NONE _ va _, NTOption ta nt) -> U.NONE ta va (mkUType sp nt)+            (_, U.UNIT _ va, NTUnit ta) -> U.UNIT ta va+            (_, U.PAIR _ va _ _, NTPair ta f1 f2 _ _) -> U.PAIR ta va f1 f2+            (_, U.CAR va f1, _) -> U.CAR va f1+            (_, U.CDR va f1, _) -> U.CDR va f1+            (STOr _ sq, U.LEFT _ va _ _ _, NTOr ta f1 f2 _ n2) ->+              U.LEFT ta va f1 f2 (mkUType sq n2)+            (STOr sp _, U.RIGHT _ va _ _ _, NTOr ta f1 f2 n1 _) ->+              U.RIGHT ta va f1 f2 (mkUType sp n1)+            (STList sp, U.NIL _ va _, NTList ta n) -> U.NIL ta va (mkUType sp n)+            (_, U.EMPTY_SET _ va ct, NTSet ta1 ta2) ->+              U.EMPTY_SET ta1 va (addCtNote ta2 ct)+            (STMap _ sq, U.EMPTY_MAP _ va ct _, NTMap ta1 ta2 n) ->+              U.EMPTY_MAP ta1 va (addCtNote ta2 ct) (mkUType sq n)+            (STBigMap _ sq, U.EMPTY_BIG_MAP _ va ct _, NTBigMap ta1 ta2 n) ->+              U.EMPTY_BIG_MAP ta1 va (addCtNote ta2 ct) (mkUType sq n)+            (STLambda sp sq, U.LAMBDA va _ _ ops, NTLambda _ n1 n2) ->+              U.LAMBDA va (mkUType sp n1) (mkUType sq n2) ops+            (_, U.CAST va _, n) -> U.CAST va (mkUType s n)+            (STOption sp, U.UNPACK va _, NTOption _ nt) -> U.UNPACK va (mkUType sp nt)+            (STOption (STContract sp), U.CONTRACT va fa _, NTOption _ (NTContract _ nt)) ->+              U.CONTRACT va fa (mkUType sp nt)+            (_, U.CONTRACT va fa t, NTOption _ _) -> U.CONTRACT va fa t+            (_, a@(U.APPLY {}), _) -> a+            (_, a@(U.CHAIN_ID {}), _) -> a+            (_, a@(U.EXT _), _) -> a+            (_, a@(U.DROP), _) -> a+            (_, a@(U.DROPN _), _) -> a+            (_, a@(U.DUP _), _) -> a+            (_, a@(U.SWAP), _) -> a+            (_, a@(U.DIG {}), _) -> a+            (_, a@(U.DUG {}), _) -> a+            (_, a@(U.IF_NONE _ _), _) -> a+            (_, a@(U.CONS _), _) -> a+            (_, a@(U.IF_LEFT _ _), _) -> a+            (_, a@(U.IF_CONS _ _), _) -> a+            (_, a@(U.SIZE _), _) -> a+            (_, a@(U.MAP _ _), _) -> a+            (_, a@(U.ITER _), _) -> a+            (_, a@(U.MEM _), _) -> a+            (_, a@(U.GET _), _) -> a+            (_, a@(U.UPDATE _), _) -> a+            (_, a@(U.IF _ _), _) -> a+            (_, a@(U.LOOP _), _) -> a+            (_, a@(U.LOOP_LEFT _), _) -> a+            (_, a@(U.EXEC _), _) -> a+            (_, a@(U.DIP _), _) -> a+            (_, a@(U.DIPN {}), _) -> a+            (_, a@(U.FAILWITH), _) -> a+            (_, a@(U.RENAME _), _) -> a+            (_, a@(U.PACK _), _) -> a+            (_, a@(U.CONCAT _), _) -> a+            (_, a@(U.SLICE _), _) -> a+            (_, a@(U.ISNAT _), _) -> a+            (_, a@(U.ADD _), _) -> a+            (_, a@(U.SUB _), _) -> a+            (_, a@(U.MUL _), _) -> a+            (_, a@(U.EDIV _), _) -> a+            (_, a@(U.ABS _), _) -> a+            (_, a@(U.NEG _), _) -> a+            (_, a@(U.LSL _), _) -> a+            (_, a@(U.LSR _), _) -> a+            (_, a@(U.OR _), _) -> a+            (_, a@(U.AND _), _) -> a+            (_, a@(U.XOR _), _) -> a+            (_, a@(U.NOT _), _) -> a+            (_, a@(U.COMPARE _), _) -> a+            (_, a@(U.EQ _), _) -> a+            (_, a@(U.NEQ _), _) -> a+            (_, a@(U.LT _), _) -> a+            (_, a@(U.GT _), _) -> a+            (_, a@(U.LE _), _) -> a+            (_, a@(U.GE _), _) -> a+            (_, a@(U.INT _), _) -> a+            (_, a@(U.SELF _), _) -> a+            (_, a@(U.TRANSFER_TOKENS _), _) -> a+            (_, a@(U.SET_DELEGATE _), _) -> a+            (_, a@(U.CREATE_CONTRACT {}), _) -> a+            (_, a@(U.IMPLICIT_ACCOUNT _), _) -> a+            (_, a@(U.NOW _), _) -> a+            (_, a@(U.AMOUNT _), _) -> a+            (_, a@(U.BALANCE _), _) -> a+            (_, a@(U.CHECK_SIGNATURE _), _) -> a+            (_, a@(U.SHA256 _), _) -> a+            (_, a@(U.SHA512 _), _) -> a+            (_, a@(U.BLAKE2B _), _) -> a+            (_, a@(U.HASH_KEY _), _) -> a+            (_, a@(U.STEPS_TO_QUOTA _), _) -> a+            (_, a@(U.SOURCE _), _) -> a+            (_, a@(U.SENDER _), _) -> a+            (_, a@(U.ADDRESS _), _) -> a+            (_, b, c) -> error $ "addInstrNote: Unexpected instruction/annotation combination: " <> show (b, c)++    handleInstr :: Instr inp out -> U.ExpandedInstr+    handleInstr (InstrWithNotes _ _) = error "impossible"+    handleInstr (FrameInstr _ _) = error "impossible"     handleInstr (Seq _ _) = error "impossible"-    handleInstr Nop = []-    handleInstr (Ext (nop :: ExtInstr inp)) = [U.EXT $ extInstrToOps nop]+    handleInstr Nop = error "impossible"+    handleInstr (Ext _) = error "impossible"     handleInstr (Nested _) = error "impossible"-    handleInstr DROP = [U.DROP]-    handleInstr DUP = [U.DUP U.noAnn]-    handleInstr SWAP = [U.SWAP]+    handleInstr DocGroup{} = error "impossible"+    handleInstr DROP = U.DROP+    handleInstr (DROPN s) = U.DROPN (fromIntegral $ peanoValSing s)+    handleInstr DUP = U.DUP U.noAnn+    handleInstr SWAP = U.SWAP+    handleInstr (DIG s) = U.DIG (fromIntegral $ peanoValSing s)+    handleInstr (DUG s) = U.DUG (fromIntegral $ peanoValSing s)     handleInstr i@(PUSH val) | _ :: Instr inp1 (t ': s) <- i =       let value = untypeValue val-      in [U.PUSH U.noAnn (toUType $ fromSingT (sing @t)) value]+      in U.PUSH U.noAnn (toUType $ fromSingT (sing @t)) value     handleInstr i@NONE | _ :: Instr inp1 ('TOption a ': inp1) <- i =-      [U.NONE U.noAnn U.noAnn U.noAnn (toUType $ fromSingT (sing @a))]-    handleInstr SOME = [U.SOME U.noAnn U.noAnn U.noAnn]-    handleInstr UNIT = [U.UNIT U.noAnn U.noAnn]-    handleInstr (IF_NONE i1 i2) = [U.IF_NONE (instrToOps i1) (instrToOps i2)]-    handleInstr PAIR = [U.PAIR U.noAnn U.noAnn U.noAnn U.noAnn]-    handleInstr CAR = [U.CAR U.noAnn U.noAnn]-    handleInstr CDR = [U.CDR U.noAnn U.noAnn]+      U.NONE U.noAnn U.noAnn (toUType $ fromSingT (sing @a))+    handleInstr SOME = U.SOME U.noAnn U.noAnn+    handleInstr UNIT = U.UNIT U.noAnn U.noAnn+    handleInstr (IF_NONE i1 i2) = U.IF_NONE (instrToOps i1) (instrToOps i2)+    handleInstr PAIR = U.PAIR U.noAnn U.noAnn U.noAnn U.noAnn+    handleInstr (AnnCAR fn) = U.CAR U.noAnn fn+    handleInstr (AnnCDR fn) = U.CDR U.noAnn fn     handleInstr i@LEFT | _ :: Instr (a ': s) ('TOr a b ': s) <- i =-      [U.LEFT U.noAnn U.noAnn U.noAnn U.noAnn (toUType $ fromSingT (sing @b))]+      U.LEFT U.noAnn U.noAnn U.noAnn U.noAnn (toUType $ fromSingT (sing @b))     handleInstr i@RIGHT | _ :: Instr (b ': s) ('TOr a b ': s) <- i =-      [U.RIGHT U.noAnn U.noAnn U.noAnn U.noAnn (toUType $ fromSingT (sing @a))]-    handleInstr (IF_LEFT i1 i2) = [U.IF_LEFT (instrToOps i1) (instrToOps i2)]+      U.RIGHT U.noAnn U.noAnn U.noAnn U.noAnn (toUType $ fromSingT (sing @a))+    handleInstr (IF_LEFT i1 i2) = U.IF_LEFT (instrToOps i1) (instrToOps i2)     handleInstr i@NIL | _ :: Instr s ('TList p ': s) <- i =-      [U.NIL U.noAnn U.noAnn (toUType $ fromSingT (sing @p))]-    handleInstr CONS = [U.CONS U.noAnn]-    handleInstr (IF_CONS i1 i2) = [U.IF_CONS (instrToOps i1) (instrToOps i2)]-    handleInstr SIZE = [U.SIZE U.noAnn]+      U.NIL U.noAnn U.noAnn (toUType $ fromSingT (sing @p))+    handleInstr CONS = U.CONS U.noAnn+    handleInstr (IF_CONS i1 i2) = U.IF_CONS (instrToOps i1) (instrToOps i2)+    handleInstr SIZE = U.SIZE U.noAnn     handleInstr i@EMPTY_SET | _ :: Instr s ('TSet e ': s) <- i =-      [U.EMPTY_SET U.noAnn U.noAnn (U.Comparable (fromSingCT (sing @e)) U.noAnn)]+      U.EMPTY_SET U.noAnn U.noAnn (U.Comparable (fromSingCT (sing @e)) U.noAnn)     handleInstr i@EMPTY_MAP | _ :: Instr s ('TMap a b ': s) <- i =-      [U.EMPTY_MAP U.noAnn U.noAnn (U.Comparable (fromSingCT (sing @a)) U.noAnn)+      U.EMPTY_MAP U.noAnn U.noAnn (U.Comparable (fromSingCT (sing @a)) U.noAnn)        (toUType $ fromSingT (sing @b))-      ]-    handleInstr (MAP op) = [U.MAP U.noAnn $ instrToOps op]-    handleInstr (ITER op) = [U.ITER $ instrToOps op]-    handleInstr MEM = [U.MEM U.noAnn]-    handleInstr GET = [U.GET U.noAnn]-    handleInstr UPDATE = [U.UPDATE]-    handleInstr (IF op1 op2) = [U.IF (instrToOps op1) (instrToOps op2)]-    handleInstr (LOOP op) = [U.LOOP (instrToOps op)]-    handleInstr (LOOP_LEFT op) = [U.LOOP_LEFT (instrToOps op)]+    handleInstr i@EMPTY_BIG_MAP | _ :: Instr s ('TBigMap a b ': s) <- i =+      U.EMPTY_BIG_MAP U.noAnn U.noAnn (U.Comparable (fromSingCT (sing @a)) U.noAnn)+       (toUType $ fromSingT (sing @b))+    handleInstr (MAP op) = U.MAP U.noAnn $ instrToOps op+    handleInstr (ITER op) = U.ITER $ instrToOps op+    handleInstr MEM = U.MEM U.noAnn+    handleInstr GET = U.GET U.noAnn+    handleInstr UPDATE = U.UPDATE U.noAnn+    handleInstr (IF op1 op2) = U.IF (instrToOps op1) (instrToOps op2)+    handleInstr (LOOP op) = U.LOOP (instrToOps op)+    handleInstr (LOOP_LEFT op) = U.LOOP_LEFT (instrToOps op)     handleInstr i@(LAMBDA {}) | LAMBDA (VLam l) :: Instr s ('TLambda i o ': s) <- i =-      [U.LAMBDA U.noAnn (toUType $ fromSingT (sing @i))-       (toUType $ fromSingT (sing @i)) (instrToOps l)-      ]-    handleInstr EXEC = [U.EXEC U.noAnn]-    handleInstr (DIP op) = [U.DIP (instrToOps op)]-    handleInstr FAILWITH = [U.FAILWITH]+      U.LAMBDA U.noAnn (toUType $ fromSingT (sing @i))+       (toUType $ fromSingT (sing @i)) (instrToOps $ rfAnyInstr l)+    handleInstr EXEC = U.EXEC U.noAnn+    handleInstr APPLY = U.APPLY U.noAnn+    handleInstr (DIP op) = U.DIP (instrToOps op)+    handleInstr (DIPN s op) =+      U.DIPN (fromIntegral $ peanoValSing s) (instrToOps op)+    handleInstr FAILWITH = U.FAILWITH     handleInstr i@CAST | _ :: Instr (a ': s) (a ': s) <- i =-      [U.CAST U.noAnn (toUType $ fromSingT (sing @a))]-    handleInstr RENAME = [U.RENAME U.noAnn]-    handleInstr PACK = [U.PACK U.noAnn]+      U.CAST U.noAnn (toUType $ fromSingT (sing @a))+    handleInstr RENAME = U.RENAME U.noAnn+    handleInstr PACK = U.PACK U.noAnn     handleInstr i@UNPACK       | _ :: Instr ('Tc 'CBytes ': s) ('TOption a ': s) <- i =-          [U.UNPACK U.noAnn (toUType $ fromSingT (sing @a))]-    handleInstr CONCAT = [U.CONCAT U.noAnn]-    handleInstr CONCAT' = [U.CONCAT U.noAnn]-    handleInstr SLICE = [U.SLICE U.noAnn]-    handleInstr ISNAT = [U.ISNAT U.noAnn]-    handleInstr ADD = [U.ADD U.noAnn]-    handleInstr SUB = [U.SUB U.noAnn]-    handleInstr MUL = [U.MUL U.noAnn]-    handleInstr EDIV = [U.EDIV U.noAnn]-    handleInstr ABS = [U.ABS U.noAnn]-    handleInstr NEG = [U.NEG]-    handleInstr LSL = [U.LSL U.noAnn]-    handleInstr LSR = [U.LSR U.noAnn]-    handleInstr OR = [U.OR U.noAnn]-    handleInstr AND = [U.AND U.noAnn]-    handleInstr XOR = [U.XOR U.noAnn]-    handleInstr NOT = [U.NOT U.noAnn]-    handleInstr COMPARE = [U.COMPARE U.noAnn]-    handleInstr Instr.EQ = [U.EQ U.noAnn]-    handleInstr NEQ = [U.NEQ U.noAnn]-    handleInstr Instr.LT = [U.LT U.noAnn]-    handleInstr Instr.GT = [U.GT U.noAnn]-    handleInstr LE = [U.LE U.noAnn]-    handleInstr GE = [U.GE U.noAnn]-    handleInstr INT = [U.INT U.noAnn]-    handleInstr SELF = [U.SELF U.noAnn]-    handleInstr i@(CONTRACT nt)+          U.UNPACK U.noAnn (toUType $ fromSingT (sing @a))+    handleInstr CONCAT = U.CONCAT U.noAnn+    handleInstr CONCAT' = U.CONCAT U.noAnn+    handleInstr SLICE = U.SLICE U.noAnn+    handleInstr ISNAT = U.ISNAT U.noAnn+    handleInstr ADD = U.ADD U.noAnn+    handleInstr SUB = U.SUB U.noAnn+    handleInstr MUL = U.MUL U.noAnn+    handleInstr EDIV = U.EDIV U.noAnn+    handleInstr ABS = U.ABS U.noAnn+    handleInstr NEG = U.NEG U.noAnn+    handleInstr LSL = U.LSL U.noAnn+    handleInstr LSR = U.LSR U.noAnn+    handleInstr OR = U.OR U.noAnn+    handleInstr AND = U.AND U.noAnn+    handleInstr XOR = U.XOR U.noAnn+    handleInstr NOT = U.NOT U.noAnn+    handleInstr COMPARE = U.COMPARE U.noAnn+    handleInstr Instr.EQ = U.EQ U.noAnn+    handleInstr NEQ = U.NEQ U.noAnn+    handleInstr Instr.LT = U.LT U.noAnn+    handleInstr Instr.GT = U.GT U.noAnn+    handleInstr LE = U.LE U.noAnn+    handleInstr GE = U.GE U.noAnn+    handleInstr INT = U.INT U.noAnn+    handleInstr SELF = U.SELF U.noAnn+    handleInstr i@(CONTRACT nt epName)       | _ :: Instr ('Tc 'CAddress ': s) ('TOption ('TContract p) ': s) <- i =-          [U.CONTRACT (U.noAnn) (mkUType (sing @p) nt)]-    handleInstr TRANSFER_TOKENS = [U.TRANSFER_TOKENS U.noAnn]-    handleInstr SET_DELEGATE = [U.SET_DELEGATE U.noAnn]-    handleInstr CREATE_ACCOUNT = [U.CREATE_ACCOUNT U.noAnn U.noAnn]-    handleInstr i@(CREATE_CONTRACT ops)+          let fa = epNameToRefAnn epName+          in U.CONTRACT U.noAnn fa (mkUType (sing @p) nt)+    handleInstr TRANSFER_TOKENS = U.TRANSFER_TOKENS U.noAnn+    handleInstr SET_DELEGATE = U.SET_DELEGATE U.noAnn+    handleInstr i@(CREATE_CONTRACT fullContract)       | _ :: Instr-          (  'Tc 'CKeyHash-          ': 'TOption ('Tc 'CKeyHash)-          ': 'Tc 'CBool-          ': 'Tc 'CBool+          (  'TOption ('Tc 'CKeyHash)           ': 'Tc 'CMutez           ': g           ': s)-          ('TOperation ': 'Tc 'CAddress ': s) <- i-      , code :: Instr '[ 'TPair p g] '[ 'TPair ('TList 'TOperation) g] <- ops =-        let contract = U.Contract (toUType $ fromSingT (sing @p))-              (toUType $ fromSingT (sing @g)) (instrToOps code)-        in [U.CREATE_CONTRACT U.noAnn U.noAnn contract]-    handleInstr IMPLICIT_ACCOUNT = [U.IMPLICIT_ACCOUNT U.noAnn]-    handleInstr NOW = [U.NOW U.noAnn]-    handleInstr AMOUNT = [U.AMOUNT U.noAnn]-    handleInstr BALANCE = [U.BALANCE U.noAnn]-    handleInstr CHECK_SIGNATURE = [U.CHECK_SIGNATURE U.noAnn]-    handleInstr SHA256 = [U.SHA256 U.noAnn]-    handleInstr SHA512 = [U.SHA512 U.noAnn]-    handleInstr BLAKE2B = [U.BLAKE2B U.noAnn]-    handleInstr HASH_KEY = [U.HASH_KEY U.noAnn]-    handleInstr STEPS_TO_QUOTA = [U.STEPS_TO_QUOTA U.noAnn]-    handleInstr SOURCE = [U.SOURCE U.noAnn]-    handleInstr SENDER = [U.SENDER U.noAnn]-    handleInstr ADDRESS = [U.ADDRESS U.noAnn]+          ('TOperation ': 'Tc 'CAddress ': s) <- i =+        U.CREATE_CONTRACT U.noAnn U.noAnn (convertFullContract fullContract)+    handleInstr IMPLICIT_ACCOUNT = U.IMPLICIT_ACCOUNT U.noAnn+    handleInstr NOW = U.NOW U.noAnn+    handleInstr AMOUNT = U.AMOUNT U.noAnn+    handleInstr BALANCE = U.BALANCE U.noAnn+    handleInstr CHECK_SIGNATURE = U.CHECK_SIGNATURE U.noAnn+    handleInstr SHA256 = U.SHA256 U.noAnn+    handleInstr SHA512 = U.SHA512 U.noAnn+    handleInstr BLAKE2B = U.BLAKE2B U.noAnn+    handleInstr HASH_KEY = U.HASH_KEY U.noAnn+    handleInstr STEPS_TO_QUOTA = U.STEPS_TO_QUOTA U.noAnn+    handleInstr SOURCE = U.SOURCE U.noAnn+    handleInstr SENDER = U.SENDER U.noAnn+    handleInstr ADDRESS = U.ADDRESS U.noAnn+    handleInstr CHAIN_ID = U.CHAIN_ID U.noAnn  untypeStackRef :: StackRef s -> U.StackRef untypeStackRef (StackRef n) = U.StackRef (peanoVal n)@@ -235,11 +376,13 @@ untypePrintComment :: PrintComment s -> U.PrintComment untypePrintComment (PrintComment pc) = U.PrintComment $ map (second untypeStackRef) pc -extInstrToOps :: ExtInstr s -> U.ExtInstrAbstract U.ExpandedOp+extInstrToOps :: ExtInstr s -> [U.ExtInstrAbstract U.ExpandedOp] extInstrToOps = \case-  PRINT pc -> U.UPRINT (untypePrintComment pc)+  PRINT pc -> one $ U.UPRINT (untypePrintComment pc)   TEST_ASSERT (TestAssert nm pc i) ->-    U.UTEST_ASSERT $ U.TestAssert nm (untypePrintComment pc) (instrToOps i)+    one $ U.UTEST_ASSERT $+    U.TestAssert nm (untypePrintComment pc) (instrToOps i)+  DOC_ITEM{} -> []  -- It's an orphan instance, but it's better than checking all cases manually. -- We can also move this convertion to the place where `Instr` is defined,@@ -257,5 +400,3 @@     , pattern1 `eqParam1` pattern2     , instr1 `eqParam2` instr2     ]--deriving instance Typeable s => Eq (ExtInstr s)
+ src/Michelson/Typed/Doc.hs view
@@ -0,0 +1,109 @@+-- | Extracting documentation from instructions set.+module Michelson.Typed.Doc+  ( buildInstrDoc+  , modifyInstrDoc+  , cutInstrNonDoc+  ) where++import Control.Lens (at)+import Data.Default (def)+import Data.Typeable (cast)+import Prelude hiding (Ordering(..))++import Michelson.Doc+import Michelson.Typed.Instr+import Michelson.Typed.Util++someDefinitionDocItemToContractDoc :: SomeDocDefinitionItem -> State ContractDoc ()+someDefinitionDocItemToContractDoc sdi@(SomeDocDefinitionItem di) =+  modify $ flip mappend+    mempty+    { cdContents = mempty+    , cdDefinitions = someDocItemToBlock (SomeDocItem di)+    , cdDefinitionsSet = one sdi+    , cdDefinitionIds = one $ case docItemRef di of+        DocItemRef docItemId -> docItemId+    }++someDocItemToContractDoc :: SomeDocItem -> State ContractDoc ()+someDocItemToContractDoc sdi@(SomeDocItem di) = do+  () <- case docItemRef di of+    DocItemNoRef ->+      modify (<> mempty{ cdContents = someDocItemToBlock sdi })+    DocItemRef{} ->+      someDefinitionDocItemToContractDoc (SomeDocDefinitionItem di)+  forM_ @_ @_ @() (docItemDependencies di) $ \(SomeDocDefinitionItem dep) ->+    case docItemRef dep of+      DocItemRef{} -> do+        -- Taking special treatment for possible cyclic dependencies.+        isPresent <- use $ cdDefinitionsSetL . at (SomeDocDefinitionItem dep)+        case isPresent of+          Just () -> pass+          Nothing -> someDocItemToContractDoc (SomeDocItem dep)++-- | Assemble contract documentation.+buildInstrDoc :: Instr inp out -> ContractDoc+buildInstrDoc = dfsFoldInstr dfsSettings $ \case+  Ext ext -> case ext of+    DOC_ITEM sdi ->+      execState (someDocItemToContractDoc sdi) mempty+    _ -> mempty+  _ -> mempty+  where+  dfsSettings :: DfsSettings ContractDoc+  dfsSettings = def+    { dsCtorEffectsApp = CtorEffectsApp+        { ceaName = "Building DocGroup"+        , ceaApplyEffects = \resChildren _ -> \case+            i@(DocGroup grouping _) ->+              (i, docGroupContent grouping resChildren)+            i -> (i, resChildren)+        }+    }++-- | Modify all documentation items recursively.+modifyInstrAllDoc+  :: (SomeDocItem -> SomeDocItem)+  -> Instr inp out+  -> Instr inp out+modifyInstrAllDoc mapper = dfsModifyInstr def $ \case+  Ext ext -> Ext $+    case ext of+      DOC_ITEM sdi -> DOC_ITEM (mapper sdi)+      i -> i+  i -> i++-- | Recursevly traverse an instruction and modify documentation items+-- matching given type.+modifyInstrDoc+  :: DocItem i+  => (i -> i)+  -> Instr inp out+  -> Instr inp out+modifyInstrDoc mapper = modifyInstrAllDoc untypedMapper+  where+  untypedMapper sdi@(SomeDocItem di) = maybe sdi (SomeDocItem . mapper) (cast di)++-- | Leave only instructions related to documentation.+--+-- Generated documentation for resulting instruction remains the same, but+-- semantics of instruction itself gets lost.+-- We have to pass optimizer here as an argument to avoid cyclic dependencies.+cutInstrNonDoc :: (forall i o. Instr i o -> Instr i o) -> Instr inp out -> Instr s s+cutInstrNonDoc optimize = optimize . dfsFoldInstr dfsSettings step+  where+  dfsSettings :: DfsSettings (Instr s s)+  dfsSettings = def+    { dsCtorEffectsApp = CtorEffectsApp+        { ceaName = "Wrap into DocGroup"+        , ceaApplyEffects = \resChildren _ -> \case+            i@(DocGroup g _) -> (i, DocGroup g resChildren)+            i -> (i, resChildren)+        }+    }+  step :: Instr inp out -> Instr s s+  step = \case+    Ext ext -> case ext of+      DOC_ITEM di -> Ext $ DOC_ITEM di+      _ -> Nop+    _ -> Nop
+ src/Michelson/Typed/EntryPoints.hs view
@@ -0,0 +1,424 @@+-- | Utilities for lightweight entrypoints support.+module Michelson.Typed.EntryPoints+  ( EpName (..)+  , pattern NoEpName+  , epNameFromParamAnn+  , epNameToParamAnn+  , epNameFromRefAnn+  , epNameToRefAnn+  , EpNameFromRefAnnError (..)++  , EpAddress (..)+  , ParseEpAddressError (..)+  , formatEpAddress+  , mformatEpAddress+  , parseEpAddress+  , unsafeParseEpAddress++  , ParamNotes (..)+  , ArmCoord (..)+  , ArmCoords+  , ParamEpError (..)+  , mkParamNotes++  , EpLiftSequence (..)+  , EntryPointCallT (..)+  , SomeEntryPointCallT (..)+  , sepcName+  , mkEntryPointCall++  , tyImplicitAccountParam+  ) where++import Data.Default (Default(..))+import qualified Data.List.NonEmpty as NE+import Data.Singletons (Sing, SingI(..))+import qualified Data.Text as T+import Data.Typeable ((:~:)(..))+import Fmt (Buildable(..), pretty, (+|), (|+))+import Test.QuickCheck (Arbitrary(..), suchThatMap)++import Michelson.Text+import Michelson.Typed.Annotation+import Michelson.Typed.Scope+import Michelson.Typed.Sing+import Michelson.Typed.T+import Michelson.Untyped.Annotation+import Tezos.Address (Address, ParseAddressError, formatAddress, parseAddress)+import Util.Typeable++----------------------------------------------------------------------------+-- Primitives+----------------------------------------------------------------------------++-- EpName+----------------------------------------------------------------------------++-- | Entrypoint name.+--+-- Empty if this entrypoint is default one.+-- Cannot be equal to "default", the reference implementation forbids that.+-- Also, set of allowed characters should be the same as in annotations.+newtype EpName = EpNameUnsafe { unEpName :: Text }+  deriving (Show, Eq, Ord)++pattern NoEpName :: EpName+pattern NoEpName = EpNameUnsafe ""++instance Buildable EpName where+  build = \case+    NoEpName -> "<default>"+    EpNameUnsafe name -> build name++instance Default EpName where+  def = EpNameUnsafe ""++-- | Make up 'EpName' from annotation in parameter type declaration.+--+-- Returns 'Nothing' if no entrypoint is assigned here.+epNameFromParamAnn :: FieldAnn -> Maybe EpName+epNameFromParamAnn an@(Annotation a)+  | an == noAnn = Nothing+  | a == "default" = Just (EpNameUnsafe "")+  | otherwise = Just (EpNameUnsafe a)++-- | Turn entrypoint name into annotation for contract parameter declaration.+epNameToParamAnn :: EpName -> FieldAnn+epNameToParamAnn (EpNameUnsafe name)+  | name == "" = Annotation "default"+  | otherwise = Annotation name++data EpNameFromRefAnnError+  = InEpNameBadAnnotation FieldAnn+  deriving (Show, Eq)++instance Buildable EpNameFromRefAnnError where+  build = \case+    InEpNameBadAnnotation (Annotation an) ->+      "Invalid entrypoint reference `" +| an |+ "`"++-- | Make up 'EpName' from annotation which is reference to an entrypoint+-- (e.g. annotation in @CONTRACT@ instruction).+--+-- Fails if annotation is invalid.+epNameFromRefAnn :: FieldAnn -> Either EpNameFromRefAnnError EpName+epNameFromRefAnn an@(Annotation a)+  | a == "default" = Left $ InEpNameBadAnnotation an+  | otherwise = Right (EpNameUnsafe a)++-- | Turn entrypoint name into annotation used as reference to entrypoint.+epNameToRefAnn :: EpName -> FieldAnn+epNameToRefAnn (EpNameUnsafe name) =+  Annotation name++instance Arbitrary FieldAnn => Arbitrary EpName where+  arbitrary = arbitrary `suchThatMap` (rightToMaybe . epNameFromRefAnn)++-- EpAddress+----------------------------------------------------------------------------++-- | Address with optional entrypoint name attached to it.+-- TODO: come up with better name?+data EpAddress = EpAddress+  { eaAddress :: Address+    -- ^ Address itself+  , eaEntryPoint :: EpName+    -- ^ Entrypoint name (might be empty)+  } deriving (Show, Eq, Ord)++instance Buildable EpAddress where+  build = build . formatEpAddress++formatEpAddress :: EpAddress -> Text+formatEpAddress (EpAddress addr ep)+  | ep == def = formatAddress addr+  | otherwise = formatAddress addr <> "%" <> pretty ep++mformatEpAddress :: EpAddress -> MText+mformatEpAddress ea =+  let t = formatEpAddress ea+     -- Should be safe because set of characters allowed in annotations+     -- (and thus in 'EpName') is subset of characters allowed in Michelson strings.+     -- At least it will be so after [TM-293]+  in mkMTextUnsafe t++data ParseEpAddressError+  = ParseEpAddressBadAddress ParseAddressError+  | ParseEpAddressRefAnnError EpNameFromRefAnnError+  deriving (Show, Eq)++instance Buildable ParseEpAddressError where+  build = \case+    ParseEpAddressBadAddress err -> build err+    ParseEpAddressRefAnnError err -> build err++-- | Parse an address which can be suffixed with entrypoint name+-- (e.g. "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU%entrypoint").+parseEpAddress :: Text -> Either ParseEpAddressError EpAddress+parseEpAddress txt =+  let (addrTxt, mannotTxt) = T.breakOn "%" txt+  in case mannotTxt of+    "" -> do+      addr <- first ParseEpAddressBadAddress $ parseAddress addrTxt+      return $ EpAddress addr def+    annotTxt' -> do+      addr <- first ParseEpAddressBadAddress $ parseAddress addrTxt+      -- TODO [TM-293]: use some @parseAnn@ and fail if characters are invalid+      let annot = case T.stripPrefix "%" annotTxt' of+            Nothing -> error "impossible"+            Just a -> Annotation a+      epName <- first ParseEpAddressRefAnnError $ epNameFromRefAnn annot+      return $ EpAddress addr epName++unsafeParseEpAddress :: HasCallStack => Text -> EpAddress+unsafeParseEpAddress = either (error . pretty) id . parseEpAddress++instance Arbitrary FieldAnn => Arbitrary EpAddress where+  arbitrary = EpAddress <$> arbitrary <*> arbitrary++-- ParamNotes+----------------------------------------------------------------------------++-- | Annotations for contract parameter declaration.+--+-- Following the Michelson specification, this type has the following invariants:+-- 1. No entrypoint name is duplicated.+-- 2. If @default@ entrypoint is explicitly assigned, no "arm" remains uncallable.+newtype ParamNotes (t :: T) = ParamNotesUnsafe+  { unParamNotes :: Notes t+  } deriving (Show, Eq)++-- | Coordinates of "arm" in Or tree, used solely in error messages.+type ArmCoords = [ArmCoord]+data ArmCoord = AcLeft | AcRight+  deriving (Show, Eq)++instance Buildable ArmCoord where+  build = \case+    AcLeft -> "left"+    AcRight -> "right"++-- | Errors specific to parameter type declaration (entrypoints).+data ParamEpError+  = ParamEpDuplicatedNames (NonEmpty EpName)+  | ParamEpUncallableArm ArmCoords+  deriving (Show, Eq)++instance Buildable ParamEpError where+  build = \case+    ParamEpDuplicatedNames names -> mconcat+      [ "Duplicated entrypoint names: "+      , mconcat . intersperse ", " $ map (surround "'" "'" . build) (toList names)+      ]+    ParamEpUncallableArm arm -> mconcat+      [ "Due to presence of 'default' entrypoint, one of contract \"arms\" \+        \cannot be called: \""+      , mconcat . intersperse " - " $ map build arm+      , "\""+      , if length arm > 1 then " (in top-to-bottom order)" else ""+      ]+    where+    surround pre post builder = pre <> builder <> post++-- | Check whether given notes are valid parameter notes.+verifyParamNotes :: Notes t -> Either ParamEpError ()+verifyParamNotes notes = do+  let allEps = appEndo (gatherEntrypoints notes) []+      duplicatedEps = mapMaybe (safeHead . tail) . NE.group $ sort allEps+  whenJust (nonEmpty duplicatedEps) $ \dups ->+    Left $ ParamEpDuplicatedNames dups++  void $ ensureAllCallable notes+    & first ParamEpUncallableArm+  where+    gatherEntrypoints :: Notes t -> Endo [EpName]+    gatherEntrypoints = \case+      NTOr _ fn1 fn2 l r -> mconcat+        [ Endo $ maybe id (:) (epNameFromParamAnn fn1)+        , Endo $ maybe id (:) (epNameFromParamAnn fn2)+        , gatherEntrypoints l+        , gatherEntrypoints r+        ]+      _ -> mempty++    -- Here we can assume that there is no more than one @default@ entrypoint,+    -- because duplications check occurs earlier.+    --+    -- In case when multiple entrypoints are uncallable, the reference+    -- implementation prefers displaying (in error message) arms which are+    -- closer to the root, but here we don't do this because that would be+    -- some more complex to implement and not sure how much does it worth that.+    ensureAllCallable :: Notes t -> Either ArmCoords Bool+    ensureAllCallable = \case+      NTOr _ fnL fnR l r -> do+        let epNameL = epNameFromParamAnn fnL+        let epNameR = epNameFromParamAnn fnR++        haveDefLL <- first (AcLeft :) $ ensureAllCallable l+        haveDefRR <- first (AcRight :) $ ensureAllCallable r+        let haveDefL = or [haveDefLL, epNameL == Just (def @EpName)]+        let haveDefR = or [haveDefRR, epNameR == Just (def @EpName)]++        when haveDefL $+          first (AcRight :) $ checkAllEpsNamed epNameR r+        when haveDefR $+          first (AcLeft :) $ checkAllEpsNamed epNameL l++        return $ or [haveDefL, haveDefR]++      _ -> return False++    checkAllEpsNamed :: Maybe EpName -> Notes t -> Either ArmCoords ()+    checkAllEpsNamed epNameRoot+      | isJust epNameRoot = \_ -> pass+      | otherwise = \case+          NTOr _ fnL fnR l r -> do+            let epNameL = epNameFromParamAnn fnL+                epNameR = epNameFromParamAnn fnR+            first (AcLeft :) $ checkAllEpsNamed epNameL l+            first (AcRight :) $ checkAllEpsNamed epNameR r+          _ -> Left []++-- | Construct 'ParamNotes' performing all necessary checks.+mkParamNotes :: Notes t -> Either ParamEpError (ParamNotes t)+mkParamNotes nt = verifyParamNotes nt $> ParamNotesUnsafe nt++----------------------------------------------------------------------------+-- Entrypoint logic+----------------------------------------------------------------------------++-- | Describes how to construct full contract parameter from given entrypoint+-- argument.+--+-- This could be just wrapper over @Value arg -> Value param@, but we cannot+-- use @Value@ type in this module easily.+data EpLiftSequence (arg :: T) (param :: T) where+  EplArgHere :: EpLiftSequence arg arg+  EplWrapLeft :: EpLiftSequence arg subparam -> EpLiftSequence arg ('TOr subparam r)+  EplWrapRight :: EpLiftSequence arg subparam -> EpLiftSequence arg ('TOr l subparam)++deriving instance Eq (EpLiftSequence arg param)+deriving instance Show (EpLiftSequence arg param)++instance Buildable (EpLiftSequence arg param) where+  build = \case+    EplArgHere -> "×"+    EplWrapLeft es -> "Left (" <> build es <> ")"+    EplWrapRight es -> "Right (" <> build es <> ")"++-- | Reference for calling a specific entrypoint of type @arg@.+data EntryPointCallT (param :: T) (arg :: T) = EntryPointCall+  { epcName :: EpName+    -- ^ Name of entrypoint.+  , epcParamProxy :: Proxy param+    -- ^ Proxy of parameter, to make parameter type more easily fetchable.+  , epcLiftSequence :: EpLiftSequence arg param+    -- ^ How to call this entrypoint in the corresponding contract.+  }++deriving instance Eq (EntryPointCallT param arg)+deriving instance Show (EntryPointCallT param arg)++instance Buildable (EntryPointCallT param arg) where+  build EntryPointCall{..} =+    "Call " +| epcName |+ ": " +| epcLiftSequence |+ ""++-- | Calls the default entrypoint.+instance (param ~ arg) => Default (EntryPointCallT param arg) where+  def = EntryPointCall+    { epcName = def+    , epcParamProxy = Proxy+    , epcLiftSequence = EplArgHere+    }++-- | 'EntryPointCallT' with hidden parameter type.+--+-- This requires argument to satisfy 'ParameterScope' constraint.+-- Strictly speaking, entrypoint argument may one day start having different+-- set of constraints comparing to ones applied to parameter, but this seems+-- unlikely.+data SomeEntryPointCallT (arg :: T) =+  forall param. (ParameterScope param) =>+  SomeEpc (EntryPointCallT param arg)++instance Eq (SomeEntryPointCallT arg) where+  SomeEpc epc1 == SomeEpc epc2 = isJust @() $ do+    Refl <- eqP (epcParamProxy epc1) (epcParamProxy epc2)+    guard (epc1 == epc2)++deriving instance Show (SomeEntryPointCallT arg)++instance Buildable (SomeEntryPointCallT arg) where+  build (SomeEpc epc) = build epc++instance ParameterScope arg => Default (SomeEntryPointCallT arg) where+  def = SomeEpc def++sepcName :: SomeEntryPointCallT arg -> EpName+sepcName (SomeEpc epc) = epcName epc++-- | Build 'EpLiftSequence'.+--+-- Here we accept entrypoint name and type information for the parameter+-- of target contract.+--+-- Returns 'Nothing' if entrypoint is not found.+-- Does not treat default entrypoints specially.+withEpLiftSequence+  :: (ParameterScope param)+  => EpName+  -> (Sing param, Notes param)+  -> (forall arg. (ParameterScope arg) => (Notes arg, EpLiftSequence arg param) -> r)+  -> Maybe r+withEpLiftSequence epName@(epNameToParamAnn -> epAnn) param cont =+  case param of+    (STOr lSing rSing, NTOr _ lFieldAnn rFieldAnn lNotes rNotes) ->+      case (checkOpPresence lSing, checkNestedBigMapsPresence lSing) of+        (OpAbsent, NestedBigMapsAbsent) -> asum+          [ guard (lFieldAnn == epAnn) $> cont (lNotes, EplWrapLeft EplArgHere)+          , guard (rFieldAnn == epAnn) $> cont (rNotes, EplWrapRight EplArgHere)+          , withEpLiftSequence epName (lSing, lNotes) (cont . fmap @((,) _) EplWrapLeft)+          , withEpLiftSequence epName (rSing, rNotes) (cont . fmap @((,) _) EplWrapRight)+          ]+    _ -> Nothing++-- | Build 'EntryPointCallT'.+--+-- Here we accept entrypoint name and type information for the parameter+-- of target contract.+--+-- Returns 'Nothing' if entrypoint is not found.+mkEntryPointCall+  :: (ParameterScope param)+  => EpName+  -> (Sing param, Notes param)+  -> (forall arg. (ParameterScope arg) => (Notes arg, EntryPointCallT param arg) -> r)+  -> Maybe r+mkEntryPointCall epName param@(_, paramNotes) cont =+  asum+  [ withEpLiftSequence epName param $ \(argInfo, liftSeq) ->+      cont . (argInfo, ) $ EntryPointCall+        { epcName = epName+        , epcParamProxy = Proxy+        , epcLiftSequence = liftSeq+        }+  , do+      guard (epName == def)+      return $ cont . (paramNotes, ) $ EntryPointCall+        { epcName = def+        , epcParamProxy = Proxy+        , epcLiftSequence = EplArgHere+        }+  ]++-- | For implicit account, which type its parameter seems to have+-- from outside.+tyImplicitAccountParam :: (Sing 'TUnit, Notes 'TUnit)+tyImplicitAccountParam = (sing, starNotes)++-- TODO [TM-280]: We also need to be able to handle field annotation in root+-- of parameter's @or@ tree.+-- Currently we don't even support field annotation at such position.+--+-- Also it would be nice to automatically add @%root@ annotation in each parameter+-- declaration when compiling Lorentz to Michelson.
src/Michelson/Typed/Extract.hs view
@@ -1,174 +1,114 @@-{-# LANGUAGE DataKinds, GADTs #-}---- Module, containing functions to convert @Michelson.Types.Type@ to+-- | Module, containing functions to convert @Michelson.Untyped.Type@ to -- @Michelson.Typed.T.T@ Michelson type representation (type stripped off all -- annotations) and to @Michelson.Typed.Annotation.Notes@ value (which contains -- field and type annotations for a given Michelson type). ----- I.e. @Michelson.Types.Type@ is split to value @t :: T@ and value of type+-- I.e. @Michelson.Untyped.Type@ is split to value @t :: T@ and value of type -- @Notes t@ for which @t@ is a type representation of value @t@. module Michelson.Typed.Extract-  ( TypeConvergeError(..)-  , extractNotes-  , fromUType+  ( fromUType   , mkUType   , toUType+  , withUType   ) where -import Fmt (Buildable(..), (+|), (|+))+import Data.Singletons (SingI, sing) -import Michelson.Typed.Annotation (Notes(..), Notes'(..), mkNotes)-import Michelson.Typed.Sing (Sing(..), fromSingCT, fromSingT)-import Michelson.Typed.T (T(..))+import Michelson.Typed.Annotation (Notes(..))+import Michelson.Typed.Sing (Sing(..), fromSingCT, fromSingT, withSomeSingCT)+import Michelson.Typed.T (T(..), toUType) import qualified Michelson.Untyped as Un --- | Extracts 'T' type from 'Michelson.Untyped.Type'.-fromUType :: HasCallStack => Un.Type -> T-fromUType (Un.Type wholeT _) = conv wholeT-  where-    conv (Un.Tc ct) = Tc ct-    conv Un.TKey = TKey-    conv Un.TUnit = TUnit-    conv Un.TSignature = TSignature-    conv (Un.TOption _ t) = TOption (fromUType t)-    conv (Un.TList t) = TList (fromUType t)-    conv (Un.TSet (Un.Comparable ct _)) = TSet ct-    conv Un.TOperation = TOperation-    conv (Un.TContract t) = TContract (fromUType t)-    conv (Un.TPair _ _ lT rT) = TPair (fromUType lT) (fromUType rT)-    conv (Un.TOr _ _ lT rT) = TOr (fromUType lT) (fromUType rT)-    conv (Un.TLambda lT rT) = TLambda (fromUType lT) (fromUType rT)-    conv (Un.TMap (Un.Comparable key _) val) = TMap key (fromUType val)-    conv (Un.TBigMap (Un.Comparable key _) val) = TBigMap key (fromUType val)-fromUType Un.TypeParameter-  = error "Parameter implicit type cannot be represented in Typed.T"-fromUType Un.TypeStorage-  = error "Parameter implicit type cannot be represented in Typed.T"+fromUType :: Un.Type -> T+fromUType ut = withUType ut (fromSingT . fst)  mkUType :: Sing x -> Notes x -> Un.Type-mkUType sing notes = case (sing, notes) of-  (STc ct, N (NTc tn))              -> mt (Un.Tc (fromSingCT ct)) tn-  (STc ct, NStar)                    -> mt (Un.Tc (fromSingCT ct)) na-  (STKey, N (NTKey tn))             -> mt Un.TKey tn-  (STKey, NStar)                     -> mt Un.TKey na-  (STUnit, N (NTUnit tn))           -> mt Un.TUnit tn-  (STUnit, NStar)                    -> mt Un.TUnit na-  (STSignature, N (NTSignature tn)) -> mt Un.TSignature tn-  (STSignature,NStar)                -> mt Un.TSignature na-  (STOption t,N (NTOption tn fn n)) -> mt (Un.TOption fn (mkUType t n)) tn-  ((STOption t), NStar)              -> mt (Un.TOption na (mkUType t NStar)) na-  (STList t, N (NTList tn n))       -> mt (Un.TList (mkUType t n)) tn-  (STList t, NStar)                  -> mt (Un.TList (mkUType t NStar)) na-  (STSet ct, N (NTSet tn n))        -> mt (Un.TSet $ mkComp ct n) tn-  (STSet ct, NStar)                  -> mt (Un.TSet $ mkComp ct na) na-  (STOperation, N (NTOperation tn)) -> mt Un.TOperation tn-  (STOperation, NStar)               -> mt Un.TOperation na-  (STContract t, N (NTContract tn n)) ->-    mt (Un.TContract (mkUType t n)) tn-  (STContract t, NStar)              -> mt (Un.TContract (mkUType t NStar)) na-  (STPair tl tr, N (NTPair tn fl fr nl nr)) ->-    mt (Un.TPair fl fr (mkUType tl nl) (mkUType tr nr)) tn-  (STPair tl tr, NStar) ->-    mt (Un.TPair na na (mkUType tl NStar) (mkUType tr NStar)) na-  (STOr tl tr, N (NTOr tn fl fr nl nr)) ->-    mt (Un.TOr fl fr (mkUType tl nl) (mkUType tr nr)) tn-  (STOr tl tr, NStar) ->-    mt (Un.TOr na na (mkUType tl NStar) (mkUType tr NStar)) na-  (STLambda p q, N (NTLambda tn np nq)) ->-    mt (Un.TLambda (mkUType p np) (mkUType q nq)) tn-  (STLambda p q, NStar) ->-    mt (Un.TLambda (mkUType p NStar) (mkUType q NStar)) na-  (STMap k v, N (NTMap tn nk nv)) ->-    mt (Un.TMap (mkComp k nk) (mkUType v nv)) tn-  (STMap k v, NStar) ->-    mt (Un.TMap (mkComp k na) (mkUType v NStar)) na-  (STBigMap k v, N (NTBigMap tn nk nv)) ->-    mt (Un.TBigMap (mkComp k nk) (mkUType v nv)) tn-  (STBigMap k v, NStar) ->-    mt (Un.TBigMap (mkComp k na) (mkUType v NStar)) na+mkUType s notes = case (s, notes) of+  (STc ct, NTc tn)              -> Un.Type (Un.Tc (fromSingCT ct)) tn+  (STKey, NTKey tn)             -> Un.Type Un.TKey tn+  (STUnit, NTUnit tn)           -> Un.Type Un.TUnit tn+  (STSignature, NTSignature tn) -> Un.Type Un.TSignature tn+  (STChainId, NTChainId tn)     -> Un.Type Un.TChainId tn+  (STOption t, NTOption tn n)   -> Un.Type (Un.TOption (mkUType t n)) tn+  (STList t, NTList tn n)       -> Un.Type (Un.TList (mkUType t n)) tn+  (STSet ct, NTSet tn n)        -> Un.Type (Un.TSet $ mkComp ct n) tn+  (STOperation, NTOperation tn) -> Un.Type Un.TOperation tn+  (STContract t, NTContract tn n) ->+    Un.Type (Un.TContract (mkUType t n)) tn+  (STPair tl tr, NTPair tn fl fr nl nr) ->+    Un.Type (Un.TPair fl fr (mkUType tl nl) (mkUType tr nr)) tn+  (STOr tl tr, NTOr tn fl fr nl nr) ->+    Un.Type (Un.TOr fl fr (mkUType tl nl) (mkUType tr nr)) tn+  (STLambda p q, NTLambda tn np nq) ->+    Un.Type (Un.TLambda (mkUType p np) (mkUType q nq)) tn+  (STMap k v, NTMap tn nk nv) ->+    Un.Type (Un.TMap (mkComp k nk) (mkUType v nv)) tn+  (STBigMap k v, NTBigMap tn nk nv) ->+    Un.Type (Un.TBigMap (mkComp k nk) (mkUType v nv)) tn  where   mkComp t a = Un.Comparable (fromSingCT t) a-  mt = Un.Type-  na = Un.noAnn -data TypeConvergeError-  = TypeConvergeError Un.T T-  | TParameterConvergeError-  | TStorageConvergeError-  deriving (Show, Eq)+-- | Convert 'Un.Type' to the isomorphic set of information from typed world.+withUType+  :: Un.Type+  -> (forall t. (Typeable t, SingI t) => (Sing t, Notes t) -> r)+  -> r+withUType (Un.Type ut tn) cont = case ut of -instance Buildable TypeConvergeError where-  build (TypeConvergeError type1 type2) =-    "Failed to construct annotation, provided types do not match: "-    +| type1 |+ " /= " +| show type2-  build (TParameterConvergeError) =-    "Cannot converge TypeParameter"-  build (TStorageConvergeError) =-    "Cannot converge TypeStorage"+  Un.Tc tc -> withSomeSingCT tc $+    \(_ :: Sing tc) -> cont (sing @('Tc tc), NTc tn) --- | Extracts @Notes t@ type from 'Michelson.Type.Type' and corresponding--- singleton.-extractNotes :: Un.Type -> Sing t -> Either TypeConvergeError (Notes t)-extractNotes Un.TypeParameter _ = Left TParameterConvergeError-extractNotes Un.TypeStorage _ = Left TStorageConvergeError-extractNotes (Un.Type wholeT tn) s = conv wholeT s-  where-    conv :: Un.T -> Sing t -> Either TypeConvergeError (Notes t)-    conv (Un.Tc ct) (STc cst)-      | fromSingCT cst == ct = pure $ mkNotes $ NTc tn-    conv Un.TKey STKey = pure $ mkNotes $ NTKey tn-    conv Un.TUnit STUnit = pure $ mkNotes $ NTUnit tn-    conv Un.TSignature STSignature = pure $ mkNotes $ NTSignature tn-    conv (Un.TOption fn t) (STOption st) =-      mkNotes . NTOption tn fn <$> extractNotes t st-    conv (Un.TList t) (STList st) = do-      mkNotes . NTList tn <$> extractNotes t st-    conv (Un.TSet (Un.Comparable et sn)) (STSet est)-      | fromSingCT est == et = pure $ mkNotes $ NTSet tn sn-    conv Un.TOperation STOperation = pure $ mkNotes $ NTOperation tn-    conv (Un.TContract t) (STContract st) =-      mkNotes . NTContract tn <$> extractNotes t st-    conv (Un.TPair pf qf pt qt) (STPair spt sqt) =-      liftA2 (mkNotes ... NTPair tn pf qf)-             (extractNotes pt spt)-             (extractNotes qt sqt)-    conv (Un.TOr pf qf pt qt) (STOr spt sqt) = do-      liftA2 (mkNotes ... NTOr tn pf qf)-             (extractNotes pt spt)-             (extractNotes qt sqt)-    conv (Un.TLambda pt qt) (STLambda spt sqt) = do-      liftA2 (mkNotes ... NTLambda tn)-             (extractNotes pt spt)-             (extractNotes qt sqt)-    conv (Un.TMap (Un.Comparable kt kn) vt) (STMap kst svt)-       | fromSingCT kst == kt = mkNotes . NTMap tn kn  <$> extractNotes vt svt-    conv (Un.TBigMap (Un.Comparable kt kn) vt) (STBigMap kst svt)-      | fromSingCT kst == kt =-        mkNotes . NTBigMap tn kn  <$> extractNotes vt svt-    conv a (fromSingT -> b) =-      Left $ TypeConvergeError a b+  Un.TKey ->+    cont (sing @'TKey, NTKey tn) --- | Converts from 'T' to 'Michelson.Type.Type'.-toUType :: T -> Un.Type-toUType t = Un.Type (convert t) Un.noAnn-  where-    convert :: T -> Un.T-    convert (Tc a) = Un.Tc a-    convert (TKey) = Un.TKey-    convert (TUnit) = Un.TUnit-    convert (TSignature) = Un.TSignature-    convert (TOption a) = Un.TOption Un.noAnn (toUType a)-    convert (TList a) = Un.TList (toUType a)-    convert (TSet a) = Un.TSet $ Un.Comparable a Un.noAnn-    convert (TOperation) = Un.TOperation-    convert (TContract a) = Un.TContract (toUType a)-    convert (TPair a b) =-      Un.TPair Un.noAnn Un.noAnn (toUType a) (toUType b)-    convert (TOr a b) =-      Un.TOr Un.noAnn Un.noAnn (toUType a) (toUType b)-    convert (TLambda a b) =-      Un.TLambda (toUType a) (toUType b)-    convert (TMap a b) =-      Un.TMap (Un.Comparable a Un.noAnn) (toUType b)-    convert (TBigMap a b) =-      Un.TBigMap (Un.Comparable a Un.noAnn) (toUType b)+  Un.TUnit ->+    cont (sing @'TUnit, NTUnit tn)++  Un.TSignature ->+    cont (sing @'TSignature, NTSignature tn)++  Un.TChainId ->+    cont (sing @'TChainId, NTChainId tn)++  Un.TOption internalT -> withUType internalT $+    \(_ :: Sing internalT, notesInternalT :: Notes internalT) ->+      cont (sing @('TOption internalT), NTOption tn notesInternalT)++  Un.TList listT -> withUType listT $+    \(_ :: Sing listT, notesListT :: Notes listT) ->+      cont (sing @('TList listT), NTList tn notesListT)++  Un.TSet (Un.Comparable sCT nsCT) -> withSomeSingCT sCT $+    \(_ :: Sing sCT) -> cont (sing @('TSet sCT), NTSet tn nsCT)++  Un.TOperation ->+    cont (sing @'TOperation, NTOperation tn)++  Un.TContract contractT -> withUType contractT $+    \(_ :: Sing contractT, notesContractT :: Notes contractT) ->+      cont (sing @('TContract contractT), NTContract tn notesContractT)++  Un.TPair la ra lt rt ->+    withUType lt $ \(_ :: Sing lt, ln :: Notes lt) ->+      withUType rt $ \(_ :: Sing rt, rn :: Notes rt) ->+        cont (sing @('TPair lt rt), NTPair tn la ra ln rn)++  Un.TOr la ra lt rt ->+    withUType lt $ \(_ :: Sing lt, ln :: Notes lt) ->+      withUType rt $ \(_ :: Sing rt, rn :: Notes rt) ->+        cont (sing @('TOr lt rt), NTOr tn la ra ln rn)++  Un.TLambda lt rt ->+    withUType lt $ \(_ :: Sing lt, ln :: Notes lt) ->+      withUType rt $ \(_ :: Sing rt, rn :: Notes rt) ->+        cont (sing @('TLambda lt rt), NTLambda tn ln rn)++  Un.TMap (Un.Comparable keyT notesT) valT ->+    withSomeSingCT keyT $ \(_ :: Sing keyT) ->+      withUType valT $ \(_ :: Sing valT, valN :: Notes valt) ->+        cont (sing @('TMap keyT valT), NTMap tn notesT valN)++  Un.TBigMap (Un.Comparable keyT notesT) valT ->+    withSomeSingCT keyT $ \(_ :: Sing keyT) ->+      withUType valT $ \(_ :: Sing valT, valN :: Notes valt) ->+        cont (sing @('TBigMap keyT valT), NTBigMap tn notesT valN)
src/Michelson/Typed/Haskell.hs view
@@ -3,5 +3,7 @@   ( module Exports   ) where +import Michelson.Typed.Haskell.Doc as Exports import Michelson.Typed.Haskell.Instr as Exports+import Michelson.Typed.Haskell.LooseSum as Exports import Michelson.Typed.Haskell.Value as Exports hiding (GIsoValue(..))
+ src/Michelson/Typed/Haskell/Doc.hs view
@@ -0,0 +1,797 @@+{-# LANGUAGE DerivingStrategies #-}++-- Dunno why it triggers+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++-- | Documentation of types appearing in contracts.+module Michelson.Typed.Haskell.Doc+  ( ADTRep+  , WithinParens (..)+  , TypeHasDoc (..)+  , TypeDocHaskellRep+  , TypeDocMichelsonRep+  , PolyTypeHasDocC+  , SomeTypeWithDoc (..)+  , typeDocDependencies'++  , HaveCommonTypeCtor+  , IsHomomorphic+  , genericTypeDocDependencies+  , customTypeDocMdReference+  , homomorphicTypeDocMdReference+  , poly1TypeDocMdReference+  , poly2TypeDocMdReference+  , homomorphicTypeDocHaskellRep+  , concreteTypeDocHaskellRep+  , concreteTypeDocHaskellRepUnsafe+  , haskellRepNoFields+  , haskellRepStripFieldPrefix+  , homomorphicTypeDocMichelsonRep+  , concreteTypeDocMichelsonRep+  , concreteTypeDocMichelsonRepUnsafe++  , DType (..)+  , GTypeHasDoc+  , buildADTRep+  , applyWithinParens+  ) where++import Data.Char (isLower, isUpper, toLower)+import qualified Data.Kind as Kind+import Data.Singletons (SingI, demote)+import qualified Data.Text as T+import Fmt (Buildable, build, (+|), (|+))+import GHC.Generics ((:*:)(..), (:+:)(..))+import qualified GHC.Generics as G+import GHC.TypeLits (ErrorMessage(..), KnownSymbol, TypeError, symbolVal)+import Named (NamedF)+import qualified Text.Show+import Type.Showtype (Showtype(..))++import Michelson.Doc+import Michelson.Text+import Michelson.Typed.Aliases+import Michelson.Typed.EntryPoints+import Michelson.Typed.Haskell.Value+import Michelson.Typed.T+import Tezos.Address+import Tezos.Core+import Tezos.Crypto+import Util.Generic+import Util.Markdown+import Util.Named+import Util.Typeable++-- | Stands for representation of some Haskell ADT corresponding to+-- Michelson value. Type parameter @a@ is what you put in place of+-- each field of the datatype, e.g. information about field type.+--+-- Outer list layer corresponds to union, and the inner one corresponds+-- to products within constructors. Constructors and fields names are present.+type ADTRep a = NonEmpty (Text, [(Maybe Text, a)])++-- | Show given 'ADTRep' in a neat way.+buildADTRep :: forall a. (WithinParens -> a -> Markdown) -> ADTRep a -> Markdown+buildADTRep buildField = \case+  p :| [] -> renderProduct (WithinParens False) (snd p)+  ps -> (mappend (mdItalic "one of" <> " \n")) $+        mconcat . map (("+ " <> ) . (<> "\n")) $+        map (renderNamedProduct (WithinParens True)) (toList ps)+  where+    renderNamedProduct :: WithinParens -> (Text, [(Maybe Text, a)]) -> Markdown+    renderNamedProduct wp (ctor, tys) =+      mdBold (build ctor) <> " " <> renderProduct wp tys++    renderProduct :: WithinParens -> [(Maybe Text, a)] -> Markdown+    renderProduct wp = \case+      [] -> "()"+      [t] -> renderNamedField wp t+      ts -> "(" <> (mconcat . intersperse ", " $ map (renderNamedField wp) ts) <> ")"++    renderNamedField :: WithinParens -> (Maybe Text, a) -> Markdown+    renderNamedField wp (mfieldName, ty) =+      maybe "" buildFieldName mfieldName <>+      buildField wp ty++-- | Remove fields names from 'ADTRep'.+--+-- Sometimes there is no sense in showing them in the doc. Example: newtypes.+mapADTRepFields :: (Maybe Text -> Maybe Text) -> ADTRep a -> ADTRep a+mapADTRepFields f = fmap . second . fmap $ first f++-- | How field names should be displayed.+--+-- Result of this function call should appear right before rendered type+-- of that field.+buildFieldName :: Text -> Markdown+buildFieldName name = mdItalic (mdBold (build name)) |+ " :"++-- | Whether given text should be rendered grouped in parentheses+-- (if they make sense).+newtype WithinParens = WithinParens Bool++applyWithinParens :: WithinParens -> Markdown -> Markdown+applyWithinParens (WithinParens wp) txt+  | wp = "(" <> txt <> ")"+  | otherwise = txt++-- | Description for a Haskell type appearing in documentation.+class Typeable a => TypeHasDoc a where+  -- | Name of type as it appears in definitions section.+  --+  -- Each type must have its own unique name because it will be used+  -- in identifier for references.+  --+  -- Default definition derives name from Generics.+  -- If it does not fit, consider defining this function manually.+  -- (We tried using 'Data.Data' for this, but it produces names including+  -- module names which is not do we want).+  typeDocName :: Proxy a -> Text+  default typeDocName+    :: (Generic a, KnownSymbol (GenericTypeName a))+    => Proxy a -> Text+  typeDocName _ = toText $ symbolVal (Proxy @(GenericTypeName a))++  -- | Explanation of a type. Markdown formatting is allowed.+  typeDocMdDescription :: Markdown++  -- | How reference to this type is rendered, in Markdown.+  --+  -- Examples:+  -- * @[Integer](#type-integer)@,+  -- * @[Maybe](#type-Maybe) [()](#type-unit)@.+  --+  -- Consider using one of the following functions as default implementation;+  -- which one to use depends on number of type arguments in your type:+  -- * 'homomorphicTypeDocMdReference'+  -- * 'poly1TypeDocMdReference'+  -- * 'poly2TypeDocMdReference'+  --+  -- If none of them fits your purposes precisely, consider using+  -- 'customTypeDocMdReference'.+  typeDocMdReference :: Proxy a -> WithinParens -> Markdown+  default typeDocMdReference+    :: (Typeable a, IsHomomorphic a)+    => Proxy a -> WithinParens -> Markdown+  typeDocMdReference = homomorphicTypeDocMdReference++  -- | All types which this type directly contains.+  --+  -- Used in automatic types discovery.+  typeDocDependencies :: Proxy a -> [SomeTypeWithDoc]+  default typeDocDependencies+    :: (Generic a, GTypeHasDoc (G.Rep a))+    => Proxy a -> [SomeTypeWithDoc]+  typeDocDependencies = genericTypeDocDependencies++  -- | For complex types - their immediate Haskell representation.+  --+  -- For primitive types set this to 'Nothing'.+  --+  -- For homomorphic types use 'homomorphicTypeDocHaskellRep' implementation.+  --+  -- For polymorhpic types consider using 'concreteTypeDocHaskellRep' as implementation.+  --+  -- Modifier 'haskellRepNoFields' can be used to hide names of fields,+  -- beneficial for newtypes.+  --+  -- Another modifier called 'haskellRepStripFieldPrefix' can be used for datatypes+  -- to leave only meaningful part of name in every field.+  typeDocHaskellRep :: TypeDocHaskellRep a+  default typeDocHaskellRep+    :: (Generic a, GTypeHasDoc (G.Rep a), IsHomomorphic a)+    => TypeDocHaskellRep a+  typeDocHaskellRep = haskellRepStripFieldPrefix homomorphicTypeDocHaskellRep++  -- | Final michelson representation of a type.+  --+  -- For homomorphic types use 'homomorphicTypeDocMichelsonRep' implementation.+  --+  -- For polymorhpic types consider using 'concreteTypeDocMichelsonRep' as implementation.+  typeDocMichelsonRep :: TypeDocMichelsonRep a+  default typeDocMichelsonRep+    :: (SingI (ToT a), IsHomomorphic a)+    => TypeDocMichelsonRep a+  typeDocMichelsonRep = homomorphicTypeDocMichelsonRep++-- | Signature of 'typeDocHaskellRep' function.+--+-- When value is 'Just', it contains types which this type is built from.+--+-- First element of provided pair may contain name a concrete type which has+-- the same type constructor as @a@ (or just @a@ for homomorphic types), and+-- the second element of the pair - its unfolding in Haskell.+--+-- For example, for some @newtype MyNewtype = MyNewtype (Integer, Natural)@+-- we would not specify the first element in the pair because @MyNewtype@ is+-- already a concrete type, and second element would contain @(Integer, Natural)@.+-- For polymorhpic types like @newtype MyPolyNewtype a = MyPolyNewtype (Text, a)@,+-- we want to describe its representation on some example of @a@, because+-- working with type variables is too non-trivial; so the first element of+-- the pair may be e.g. @"MyPolyNewType Integer"@, and the second one shows+-- that it unfolds to @(Text, Integer)@.+--+-- When rendered, values of this type look like:+-- * @(Integer, Natural)@ - for homomorphic type.+-- * @MyError Integer = (Text, Integer)@ - concrete sample for polymorhpic type.+type TypeDocHaskellRep a =+  Proxy a -> Maybe (Maybe DocTypeRepLHS, ADTRep SomeTypeWithDoc)++-- | Signature of 'typeDocMichelsonRep' function.+--+-- As in 'TypeDocHaskellRep', set the first element of the pair to 'Nothing'+-- for primitive types, otherwise it stands as some instantiation of a type,+-- and its Michelson representation is given in the second element of the pair.+--+-- Examples of rendered representation:+-- * @pair int nat@ - for homomorphic type.+-- * @MyError Integer = pair string int@ - concrete sample for polymorhpic type.+type TypeDocMichelsonRep a =+  Proxy a -> (Maybe DocTypeRepLHS, T)++-- | Data hides some type implementing 'TypeHasDoc'.+data SomeTypeWithDoc where+  SomeTypeWithDoc :: TypeHasDoc td => Proxy td -> SomeTypeWithDoc++instance Show SomeTypeWithDoc where+  show (SomeTypeWithDoc di) = toString (typeDocName di)++-- | When rendering type's inner representation, this stands for name of+--+-- Having this makes sense for polymorhpic types, when you want to render+-- representation of some concrete instantiation of that type.+newtype DocTypeRepLHS = DocTypeRepLHS Text+  deriving newtype (IsString, Buildable)++-- | Like 'typeDocDependencies' but returns values of more common type+-- which is used in 'docItemDependencies'.+typeDocDependencies'+  :: TypeHasDoc a+  => Proxy a+  -> [SomeDocDefinitionItem]+typeDocDependencies' at =+  typeDocDependencies at <&>+    \(SomeTypeWithDoc t) -> SomeDocDefinitionItem (DType t)++-- | Doc element with description of a type.+data DType where+  DType :: TypeHasDoc a => Proxy a -> DType++instance Eq DType where+  DType a1 == DType a2 = a1 `eqExt` a2+instance Ord DType where+  DType a1 `compare` DType a2 = a1 `compareExt` a2++instance DocItem DType where+  type DocItemPosition DType = 5000+  type DocItemPlacement DType = 'DocItemInDefinitions++  docItemSectionName = Just "Types"++  docItemRef (DType a) = DocItemRef $+    DocItemId ("types-" <> typeDocName a)++  docItemDependencies (DType (ap' :: Proxy a)) =+    typeDocDependencies' ap'++  docItemToMarkdown lvl (DType (ap' :: Proxy a)) =+    mconcat . catMaybes $+    [ Just mdSeparator+    , Just $ mdHeader lvl (mdTicked . build $ typeDocName ap')+    , Just $ typeDocMdDescription @a |+ "\n\n"+    , typeDocHaskellRep ap' <&> \(mlhs, rep) ->+        let+          buildField wp (SomeTypeWithDoc di) =+            typeDocMdReference di wp+          renderedRep =+             buildADTRep buildField rep+          rendered = case mlhs of+            Nothing ->+              mdSubsection "Structure" renderedRep+            Just lhs ->+              mdSubsection "Structure (example)" $+                mdTicked (build lhs) <> " = " <> renderedRep+        in rendered <> "\n\n"+    , Just $+        let (mlhs, rep) = typeDocMichelsonRep ap'+            renderedRep = mdTicked (build rep)+            rendered = case mlhs of+              Nothing -> mdSubsection "Final Michelson representation"+                         renderedRep+              Just lhs -> mdSubsection "Final Michelson representation (example)" $+                          mdTicked (build lhs) <> " = " <> renderedRep+        in rendered <> "\n\n"+    ]++-- Default implementations+----------------------------------------------------------------------------++-- | Require two types to be built from the same type constructor.+--+-- E.g. @HaveCommonTypeCtor (Maybe Integer) (Maybe Natural)@ is defined,+-- while @HaveCmmonTypeCtor (Maybe Integer) [Integer]@ is not.+class HaveCommonTypeCtor a b+instance HaveCommonTypeCtor ac bc => HaveCommonTypeCtor (ac a) (bc b)+instance HaveCommonTypeCtor a a++-- | Require this type to be homomorphic.+class IsHomomorphic a where+instance TypeError ('Text "Type is not homomorphic: " ':<>: 'ShowType (a b)) =>+         IsHomomorphic (a b)+instance {-# OVERLAPPABLE #-} IsHomomorphic a++-- | Render a reference to a type which consists of type constructor+-- (you have to provide name of this type constructor and documentation+-- for the whole type) and zero or more type arguments.+customTypeDocMdReference :: (Text, DType) -> [DType] -> WithinParens -> Markdown+customTypeDocMdReference (typeCtorName, tyDoc) typeArgsDoc wp =+  let DocItemRef (DocItemId ctorDocItemId) = docItemRef tyDoc+  in applyWithinParens wpSmart $+     mconcat . intersperse " " $+      ( mdLocalRef (mdTicked $ build typeCtorName) ctorDocItemId+      : (typeArgsDoc <&> \(DType di) -> typeDocMdReference di (WithinParens True))+      )+    where+      -- If we are rendering an atomic thing, there is no need in parentheses+      -- around it+      wpSmart =+        let WithinParens wp' = wp+        in WithinParens (wp' && not (null typeArgsDoc))++-- | Derive 'typeDocMdReference', for homomorphic types only.+homomorphicTypeDocMdReference+  :: forall (t :: Kind.Type).+     (Typeable t, TypeHasDoc t, IsHomomorphic t)+  => Proxy t -> WithinParens -> Markdown+homomorphicTypeDocMdReference tp _ =+  customTypeDocMdReference+    (toText $ showtype tp, DType tp)+    []+    (WithinParens False)++-- | Derive 'typeDocMdReference', for polymorphic type with one+-- type argument, like @Maybe Integer@.+poly1TypeDocMdReference+  :: forall t (r :: Kind.Type) (a :: Kind.Type).+      (r ~ t a, Typeable t, Each '[TypeHasDoc] [r, a], IsHomomorphic t)+  => Proxy r -> WithinParens -> Markdown+poly1TypeDocMdReference tp =+  customTypeDocMdReference+    (toText $ showtype (Proxy @t), DType tp)+    [DType (Proxy @a)]++-- | Derive 'typeDocMdReference', for polymorphic type with two+-- type arguments, like @Lambda Integer Natural@.+poly2TypeDocMdReference+  :: forall t (r :: Kind.Type) (a :: Kind.Type) (b :: Kind.Type).+      (r ~ t a b, Typeable t, Each '[TypeHasDoc] [r, a, b], IsHomomorphic t)+  => Proxy r -> WithinParens -> Markdown+poly2TypeDocMdReference tp =+  customTypeDocMdReference+    (toText $ showtype (Proxy @t), DType tp)+    [ DType (Proxy @a)+    , DType (Proxy @b)+    ]++-- | Implement 'typeDocDependencies' via getting all immediate fields+-- of a datatype.+--+-- Note: this will not include phantom types, I'm not sure yet how this+-- scenario should be handled (@martoon).+genericTypeDocDependencies+  :: forall a.+      (Generic a, GTypeHasDoc (G.Rep a))+  => Proxy a -> [SomeTypeWithDoc]+genericTypeDocDependencies _ = do+  (_, products) <- toList $ gTypeDocHaskellRep @(G.Rep a)+  (_, ty) <- products+  return ty++-- | Implement 'typeDocHaskellRep' for a homomorphic type.+--+-- Note that it does not require your type to be of 'IsHomomorphic' instance,+-- which can be useful for some polymorhpic types which, for documentation+-- purposes, we want to consider homomorphic.+-- Example: 'Operation' is in fact polymorhpic, but we don't want this fact to+-- be reflected in the documentation.+homomorphicTypeDocHaskellRep+  :: forall a.+     (Generic a, GTypeHasDoc (G.Rep a))+  => TypeDocHaskellRep a+homomorphicTypeDocHaskellRep _ = Just+  ( Nothing+  , gTypeDocHaskellRep @(G.Rep a)+  )++-- | Implement 'typeDocHaskellRep' on example of given concrete type.+--+-- This is a best effort attempt to implement 'typeDocHaskellRep' for polymorhpic+-- types, as soon as there is no simple way to preserve type variables when+-- automatically deriving Haskell representation of a type.+concreteTypeDocHaskellRep+  :: forall a b.+     ( Typeable a, IsoValue a, Generic a, GTypeHasDoc (G.Rep a)+     , HaveCommonTypeCtor b a+     )+  => TypeDocHaskellRep b+concreteTypeDocHaskellRep = concreteTypeDocHaskellRepUnsafe @a++-- | Version of 'concreteTypeDocHaskellRep' which does not ensure+-- whether the type for which representation is built is any similar to+-- the original type which you implement a 'TypeHasDoc' instance for.+concreteTypeDocHaskellRepUnsafe+  :: forall a b.+     ( Typeable a, IsoValue a, Generic a, GTypeHasDoc (G.Rep a)+     )+  => TypeDocHaskellRep b+concreteTypeDocHaskellRepUnsafe _ = Just+  ( Just (DocTypeRepLHS . toText . showtype $ Proxy @a)+  , gTypeDocHaskellRep @(G.Rep a)+  )++-- | Erase fields from Haskell datatype representation.+--+-- Use this when rendering fields names is undesired.+haskellRepNoFields :: TypeDocHaskellRep a -> TypeDocHaskellRep a+haskellRepNoFields mkRep =+  \p -> second (mapADTRepFields (const Nothing)) <$> mkRep p++-- | Cut fields prefixes which we use according to the style guide.+--+-- E.g. @cmMyField@ field will be transformed to @myField@.+haskellRepStripFieldPrefix+  :: HasCallStack+  => TypeDocHaskellRep a -> TypeDocHaskellRep a+haskellRepStripFieldPrefix mkRep =+  \p -> second (mapADTRepFields (fmap stripPrefix)) <$> mkRep p+  where+    stripPrefix fieldName =+      case T.uncons $ T.dropWhile isLower fieldName of+        Nothing -> error $ "Field '" <> fieldName <> "' has no prefix"+        Just (c, cs) ->+          -- For fields like @ciUSPosition@ we should not lead the first letter+          -- to lower case like @uSPosition@.+          let isAbbreviation = case T.uncons cs of+                Just (c2, _)+                  | isUpper c2 -> True+                  | otherwise -> False+                Nothing -> False+          in T.cons (if isAbbreviation then c else toLower c) cs++-- | Implement 'typeDocMichelsonRep' for homomorphic type.+homomorphicTypeDocMichelsonRep+  :: forall a.+     SingI (ToT a)+  => TypeDocMichelsonRep a+homomorphicTypeDocMichelsonRep _ =+  ( Nothing+  , demote @(ToT a)+  )++-- | Implement 'typeDocMichelsonRep' on example of given concrete type.+--+-- This function exists for the same reason as 'concreteTypeDocHaskellRep'.+concreteTypeDocMichelsonRep+  :: forall a b.+     (Typeable a, SingI (ToT a), HaveCommonTypeCtor b a)+  => TypeDocMichelsonRep b+concreteTypeDocMichelsonRep _ =+  ( Just (DocTypeRepLHS . toText . showtype $ Proxy @a)+  , demote @(ToT a)+  )++-- | Version of 'concreteTypeDocHaskellRepUnsafe' which does not ensure+-- whether the type for which representation is built is any similar to+-- the original type which you implement a 'TypeHasDoc' instance for.+concreteTypeDocMichelsonRepUnsafe+  :: forall a b.+     (Typeable a, SingI (ToT a))+  => TypeDocMichelsonRep b+concreteTypeDocMichelsonRepUnsafe _ =+  ( Just (DocTypeRepLHS . toText . showtype $ Proxy @a)+  , demote @(ToT a)+  )++-- | Generic traversal for automatic deriving of some methods in 'TypeHasDoc'.+class GTypeHasDoc (x :: Kind.Type -> Kind.Type) where+  gTypeDocHaskellRep :: ADTRep SomeTypeWithDoc++instance GTypeHasDoc x => GTypeHasDoc (G.D1 i x) where+  gTypeDocHaskellRep = gTypeDocHaskellRep @x++instance (GTypeHasDoc x, GTypeHasDoc y) => GTypeHasDoc (x :+: y) where+  gTypeDocHaskellRep = gTypeDocHaskellRep @x <> gTypeDocHaskellRep @y++instance (GProductHasDoc x, KnownSymbol ctor) =>+         GTypeHasDoc (G.C1 ('G.MetaCons ctor _1 _2) x) where+  gTypeDocHaskellRep = one $+    ( toText $ symbolVal (Proxy @ctor)+    , gProductDocHaskellRep @x+    )++instance TypeError ('Text "Cannot derive documentation for void-like type") =>+    GTypeHasDoc G.V1 where+  gTypeDocHaskellRep = error "impossible"++-- | Product type traversal for 'TypeHasDoc'.+class GProductHasDoc (x :: Kind.Type -> Kind.Type) where+  gProductDocHaskellRep :: [(Maybe Text, SomeTypeWithDoc)]++instance (GProductHasDoc x, GProductHasDoc y) => GProductHasDoc (x :*: y) where+  gProductDocHaskellRep = gProductDocHaskellRep @x <> gProductDocHaskellRep @y++instance TypeHasDoc a =>+         GProductHasDoc (G.S1 ('G.MetaSel 'Nothing _1 _2 _3) (G.Rec0 a)) where+  gProductDocHaskellRep = one (Nothing, SomeTypeWithDoc (Proxy @a))++instance (TypeHasDoc a, KnownSymbol field) =>+         GProductHasDoc (G.S1 ('G.MetaSel ('Just field) _1 _2 _3) (G.Rec0 a)) where+  gProductDocHaskellRep = one+    ( Just $ toText (symbolVal $ Proxy @field)+    , SomeTypeWithDoc (Proxy @a)+    )++instance GProductHasDoc G.U1 where+  gProductDocHaskellRep = mempty++-- Instances+----------------------------------------------------------------------------++-- | Constraint, required when deriving 'TypeHasDoc' for polymorphic type+-- with the least possible number of methods defined manually.+type PolyTypeHasDocC ts = Each '[TypeHasDoc] ts++-- | Version of 'PolyTypeHasDocC' for comparable types.+type PolyCTypeHasDocC ts = Each '[TypeHasDoc] ts++instance TypeHasDoc Integer where+  typeDocName _ = "Integer"+  typeDocMdDescription = "Signed number."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc Natural where+  typeDocName _ = "Natural"+  typeDocMdDescription = "Unsigned number."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc MText where+  typeDocName _ = "Text"+  typeDocMdReference p = customTypeDocMdReference ("Text", DType p) []+  typeDocMdDescription =+    "Michelson string.\n\+    \Not every text literal is valid string, see list of constraints in the \+    \[Official Michelson documentation](http://tezos.gitlab.io/zeronet/whitedoc/michelson.html#constants)."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc Bool where+  typeDocName _ = "Bool"+  typeDocMdDescription = "Bool primitive."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc ByteString where+  typeDocName _ = "ByteString"+  typeDocMdDescription = "Bytes primitive."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc Mutez where+  typeDocName _ = "Mutez"+  typeDocMdDescription = "Mutez primitive."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc KeyHash where+  typeDocName _ = "KeyHash"+  typeDocMdDescription = "KeyHash primitive."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc Timestamp where+  typeDocName _ = "Timestamp"+  typeDocMdDescription = "Timestamp primitive."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc Address where+  typeDocName _ = "Address simplified"+  typeDocMdDescription =+    "This is similar to Michelson Address, but does not retain entrypoint name \+    \if it refers to a contract."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc EpAddress where+  typeDocName _ = "Address"+  typeDocMdDescription = "Address primitive."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc PublicKey where+  typeDocName _ = "PublicKey"+  typeDocMdDescription = "PublicKey primitive."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc Signature where+  typeDocName _ = "Signature"+  typeDocMdDescription = "Signature primitive."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing++instance TypeHasDoc () where+  typeDocName _ = "()"+  typeDocMdDescription = "Unit primitive."+  typeDocDependencies _ = []++instance PolyTypeHasDocC '[a] => TypeHasDoc [a] where+  typeDocName _ = "List"+  typeDocMdDescription = "List primitive."+  typeDocMdReference _ =+    -- poly1TypeDocMdReference would produce text like @[] Integer@, we want+    -- to replace this @[]@ with @List@.+    customTypeDocMdReference ("List", DType (Proxy @[a])) [DType (Proxy @a)]+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep = concreteTypeDocMichelsonRep @[Integer]++instance PolyTypeHasDocC '[a] => TypeHasDoc (Maybe a) where+  typeDocMdDescription = "Option primitive."+  typeDocMdReference = poly1TypeDocMdReference+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep = concreteTypeDocMichelsonRep @(Maybe Integer)++instance PolyTypeHasDocC [l, r] => TypeHasDoc (Either l r) where+  typeDocMdDescription = "Or primitive."+  typeDocMdReference = poly2TypeDocMdReference+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep = concreteTypeDocMichelsonRep @(Either Integer Natural)++instance PolyTypeHasDocC [a, b] => TypeHasDoc (a, b) where+  typeDocName _ = "(a, b)"+  typeDocMdReference _ = tupleTypeDocReference+    [ typeDocMdReference (Proxy @a) (WithinParens False)+    , typeDocMdReference (Proxy @b) (WithinParens False)+    ]+  typeDocMdDescription = "Pair primitive."+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep = concreteTypeDocMichelsonRep @(Integer, Natural)++instance PolyCTypeHasDocC '[a] => TypeHasDoc (Set a) where+  typeDocName _ = "Set"+  typeDocMdReference = poly1TypeDocMdReference+  typeDocMdDescription = "Set primitive."+  typeDocDependencies _ = [SomeTypeWithDoc (Proxy @a)]+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep = concreteTypeDocMichelsonRep @(Set Integer)++instance TypeHasDoc Operation where+  typeDocName _ = "Operation"+  typeDocMdReference tp = customTypeDocMdReference ("Operation", DType tp) []+  typeDocMdDescription = "Operation primitive."+  typeDocDependencies _ = []+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep = homomorphicTypeDocMichelsonRep++instance PolyTypeHasDocC '[cp] => TypeHasDoc (ContractRef cp) where+  typeDocName _ = "Contract"+  typeDocMdReference = poly1TypeDocMdReference+  typeDocMdDescription = "Contract primitive with given type of parameter."+  typeDocDependencies _ = [SomeTypeWithDoc (Proxy @cp)]+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep = concreteTypeDocMichelsonRep @(ContractRef Integer)++instance (PolyCTypeHasDocC '[k], PolyTypeHasDocC '[v], Ord k) =>+         TypeHasDoc (Map k v) where+  typeDocName _ = "Map"+  typeDocMdReference = poly2TypeDocMdReference+  typeDocMdDescription = "Map primitive."+  typeDocDependencies _ = [SomeTypeWithDoc (Proxy @k), SomeTypeWithDoc (Proxy @v)]+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep = concreteTypeDocMichelsonRep @(Map Integer Natural)++instance (PolyCTypeHasDocC '[k], PolyTypeHasDocC '[v], Ord k) =>+         TypeHasDoc (BigMap k v) where+  typeDocName _ = "BigMap"+  typeDocMdReference = poly2TypeDocMdReference+  typeDocMdDescription = "BigMap primitive."+  typeDocDependencies _ = [SomeTypeWithDoc (Proxy @k), SomeTypeWithDoc (Proxy @v)]+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep = concreteTypeDocMichelsonRep @(BigMap Integer Natural)+++tupleTypeDocReference :: [Markdown] -> WithinParens -> Markdown+tupleTypeDocReference vs _ = "(" +| mconcat (intersperse ", " $ map build vs) |+ ")"++instance PolyTypeHasDocC [a, b, c] => TypeHasDoc (a, b, c) where+  typeDocName _ = "(a, b, c)"+  typeDocMdReference _ = tupleTypeDocReference+    [ typeDocMdReference (Proxy @a) (WithinParens False)+    , typeDocMdReference (Proxy @b) (WithinParens False)+    , typeDocMdReference (Proxy @c) (WithinParens False)+    ]+  typeDocMdDescription = "Tuple of size 3."+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep = concreteTypeDocMichelsonRep @(Integer, Natural, MText)++instance PolyTypeHasDocC [a, b, c, d] => TypeHasDoc (a, b, c, d) where+  typeDocName _ = "(a, b, c, d)"+  typeDocMdReference _ = tupleTypeDocReference+    [ typeDocMdReference (Proxy @a) (WithinParens False)+    , typeDocMdReference (Proxy @b) (WithinParens False)+    , typeDocMdReference (Proxy @c) (WithinParens False)+    , typeDocMdReference (Proxy @d) (WithinParens False)+    ]+  typeDocMdDescription = "Tuple of size 4."+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep =+    -- Starting from tuple of size 4 the exact types should not matter to a reader,+    -- rather the resulting pairs tree.+    concreteTypeDocMichelsonRep @((), (), (), ())++instance PolyTypeHasDocC [a, b, c, d, e] => TypeHasDoc (a, b, c, d, e) where+  typeDocName _ = "(a, b, c, d, e)"+  typeDocMdDescription = "Tuple of size 5."+  typeDocMdReference _ = tupleTypeDocReference+    [ typeDocMdReference (Proxy @a) (WithinParens False)+    , typeDocMdReference (Proxy @b) (WithinParens False)+    , typeDocMdReference (Proxy @c) (WithinParens False)+    , typeDocMdReference (Proxy @d) (WithinParens False)+    , typeDocMdReference (Proxy @e) (WithinParens False)+    ]+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep =+    concreteTypeDocMichelsonRep @((), (), (), (), ())++instance PolyTypeHasDocC [a, b, c, d, e, f] => TypeHasDoc (a, b, c, d, e, f) where+  typeDocName _ = "(a, b, c, d, e, f)"+  typeDocMdReference _ = tupleTypeDocReference+    [ typeDocMdReference (Proxy @a) (WithinParens False)+    , typeDocMdReference (Proxy @b) (WithinParens False)+    , typeDocMdReference (Proxy @c) (WithinParens False)+    , typeDocMdReference (Proxy @d) (WithinParens False)+    , typeDocMdReference (Proxy @e) (WithinParens False)+    , typeDocMdReference (Proxy @f) (WithinParens False)+    ]+  typeDocMdDescription = "Tuple of size 6."+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep =+    concreteTypeDocMichelsonRep @((), (), (), (), (), ())++instance PolyTypeHasDocC [a, b, c, d, e, f, g] => TypeHasDoc (a, b, c, d, e, f, g) where+  typeDocName _ = "(a, b, c, d, e, f, g)"+  typeDocMdReference _ = tupleTypeDocReference+    [ typeDocMdReference (Proxy @a) (WithinParens False)+    , typeDocMdReference (Proxy @b) (WithinParens False)+    , typeDocMdReference (Proxy @c) (WithinParens False)+    , typeDocMdReference (Proxy @d) (WithinParens False)+    , typeDocMdReference (Proxy @e) (WithinParens False)+    , typeDocMdReference (Proxy @f) (WithinParens False)+    , typeDocMdReference (Proxy @g) (WithinParens False)+    ]+  typeDocMdDescription = "Tuple of size 7."+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep =+    concreteTypeDocMichelsonRep @((), (), (), (), (), (), ())+++instance ( TypeHasDoc (ApplyNamedFunctor f a)+         , KnownSymbol n+         , SingI (ToT (ApplyNamedFunctor f Integer))+         , Typeable f, Typeable a+         ) =>+         TypeHasDoc (NamedF f a n) where+  typeDocName _ = "Named entry"+  typeDocMdReference _ wp =+    applyWithinParens wp $+    buildFieldName (toText (symbolVal $ Proxy @n)) +| " " +|+    typeDocMdReference (Proxy @(ApplyNamedFunctor f a)) (WithinParens False) |+ ""+  typeDocDependencies _ =+    [SomeTypeWithDoc (Proxy @(ApplyNamedFunctor f a)), SomeTypeWithDoc (Proxy @Integer)]+  typeDocHaskellRep _ = Nothing+  typeDocMichelsonRep _ = (Just "number: Integer", demote @(ToT (ApplyNamedFunctor f Integer)))+  typeDocMdDescription =+    "Some entries have names for clarity.\n\n\+    \In resulting Michelson names may be mapped to annotations."
src/Michelson/Typed/Haskell/Instr/Helpers.hs view
@@ -1,12 +1,8 @@ module Michelson.Typed.Haskell.Instr.Helpers   ( Branch (..)   , Path-  , RSplit (..)   ) where -import Data.Vinyl.Core (Rec(..))-import Data.Vinyl.TypeLevel (type (++))- -- | Which branch to choose in generic tree representation: left, -- straight or right. 'S' is used when there is one constructor with -- one field (something newtype-like).@@ -20,15 +16,3 @@  -- | Path to a leaf (some field or constructor) in generic tree representation. type Path = [Branch]---- | Split a record into two pieces.-class RSplit (l :: [k]) (r :: [k]) where-  rsplit :: forall f. Rec f (l ++ r) -> (Rec f l, Rec f r)--instance RSplit '[] r where-  rsplit = (RNil, )--instance RSplit ls r => RSplit (l ': ls) r where-  rsplit (x :& r) =-    let (x1, r1) = rsplit r-    in (x :& x1, r1)
src/Michelson/Typed/Haskell/Instr/Product.hs view
@@ -31,6 +31,7 @@ import Michelson.Typed.Instr import Michelson.Text import Util.Named (NamedInner)+import Util.Type  -- Fields lookup (helper) ----------------------------------------------------------------------------
src/Michelson/Typed/Haskell/Instr/Sum.hs view
@@ -16,7 +16,11 @@   , CaseClauseParam (..)   , CaseClause (..)   , CaseClauses+  , GCaseClauses+  , GCaseBranchInput +  , Branch (..)+  , Path   , CtorField (..)   , ExtractCtorField   , AppendCtorField@@ -26,6 +30,9 @@   , CtorHasOnlyField   , CtorOnlyField   , MyCompoundType++    -- * Helpers+  , IsPrimitiveValue   ) where  import Data.Constraint (Dict(..))@@ -39,7 +46,7 @@ import GHC.Generics ((:*:)(..), (:+:)(..)) import qualified GHC.Generics as G import GHC.TypeLits (AppendSymbol, ErrorMessage(..), Symbol, TypeError)-import Named ((:!))+import Named ((:!), NamedF) import Type.Reflection ((:~:)(Refl)) import Unsafe.Coerce (unsafeCoerce) @@ -47,11 +54,12 @@ import Michelson.Typed.Haskell.Value import Michelson.Typed.Instr import Michelson.Typed.T-import Michelson.Text (mt)+import Michelson.Text (MText, mt) import Michelson.Typed.Value import Tezos.Address (Address) import Tezos.Core (Mutez, Timestamp) import Tezos.Crypto (KeyHash, PublicKey, Signature)+import Util.Type import Util.TypeTuple  -- Constructors lookup (helper)@@ -173,26 +181,36 @@   GCanGoDeeper x = TypeError     ('Text "GCanGoDeeper encountered unexpected pattern: " ':<>: 'ShowType x) +-- | Whether given type represents an atomic Michelson value.+type family IsPrimitiveValue (x :: Kind.Type) :: Bool where+  IsPrimitiveValue (Maybe _) = 'True+  IsPrimitiveValue (NamedF _ _ _) = 'True+  IsPrimitiveValue Integer = 'True+  IsPrimitiveValue Natural = 'True+  IsPrimitiveValue Text = 'True+  IsPrimitiveValue MText = 'True+  IsPrimitiveValue Bool = 'True+  IsPrimitiveValue ByteString = 'True+  IsPrimitiveValue Mutez = 'True+  IsPrimitiveValue Address = 'True+  IsPrimitiveValue KeyHash = 'True+  IsPrimitiveValue Timestamp = 'True+  IsPrimitiveValue PublicKey = 'True+  IsPrimitiveValue Signature = 'True+  IsPrimitiveValue (ContractRef _) = 'True+  IsPrimitiveValue (BigMap _ _) = 'True+  IsPrimitiveValue (Map _ _) = 'True+  IsPrimitiveValue (Set _) = 'True+  IsPrimitiveValue ([_]) = 'True+  IsPrimitiveValue (Operation' _) = 'True+  IsPrimitiveValue _ = 'False+ -- Some types don't have Generic instances (e. g. primitives like Integer), so -- we need another type family to handle them.-type family CanGoDeeper (x :: Kind.Type) :: Bool where-  CanGoDeeper Integer = 'False-  CanGoDeeper Natural = 'False-  CanGoDeeper Text = 'False-  CanGoDeeper Bool = 'False-  CanGoDeeper ByteString = 'False-  CanGoDeeper Mutez = 'False-  CanGoDeeper Address = 'False-  CanGoDeeper KeyHash = 'False-  CanGoDeeper Timestamp = 'False-  CanGoDeeper PublicKey = 'False-  CanGoDeeper Signature = 'False-  CanGoDeeper (ContractAddr _) = 'False-  CanGoDeeper (BigMap _ _) = 'False-  CanGoDeeper (Map _ _) = 'False-  CanGoDeeper (Set _) = 'False-  CanGoDeeper ([_]) = 'False-  CanGoDeeper x = GCanGoDeeper (G.Rep x)+type CanGoDeeper (x :: Kind.Type) =+  If (IsPrimitiveValue x)+     'False+     (GCanGoDeeper (G.Rep x))  type family GLookupNamedDeeper (name :: Symbol) (x :: Kind.Type -> Kind.Type)           :: Maybe LookupNamedResult where@@ -433,6 +451,15 @@ _wrapMyEnum2 :: Instr (ToT Integer ': s) (ToT MyEnum ': s) _wrapMyEnum2 = instrWrap @MyEnum #cCaseN +data MyTypeWithNamedField+  = MeaninglessCtor+  | CtorWithNamedField ("name" :! Natural)+  deriving stock Generic+  deriving anyclass IsoValue++_accessMyTypeWithNamedField :: Instr (ToT Natural ': s) (ToT MyTypeWithNamedField ': s)+_accessMyTypeWithNamedField = instrWrap @MyTypeWithNamedField #cCtorWithNamedField+ ---------------------------------------------------------------------------- -- "case" instruction ----------------------------------------------------------------------------@@ -441,7 +468,7 @@ instrCase   :: forall dt out inp.      InstrCaseC dt inp out-  => Rec (CaseClause inp out) (CaseClauses dt) -> Instr (ToT dt ': inp) out+  => Rec (CaseClause inp out) (CaseClauses dt) -> RemFail Instr (ToT dt ': inp) out instrCase = gInstrCase @(G.Rep dt)  type InstrCaseC dt inp out =@@ -456,7 +483,9 @@  -- | Type information about single case clause. data CaseClause (inp :: [T]) (out :: [T]) (param :: CaseClauseParam) where-  CaseClause :: Instr (AppendCtorField x inp) out -> CaseClause inp out ('CaseClauseParam ctor x)+  CaseClause+    :: RemFail Instr (AppendCtorField x inp) out+    -> CaseClause inp out ('CaseClauseParam ctor x)  -- | Lift an instruction to case clause. --@@ -468,7 +497,7 @@ -- some mistakes. (//->)   :: Label ("c" `AppendSymbol` ctor)-  -> Instr (AppendCtorField x inp) out+  -> RemFail Instr (AppendCtorField x inp) out   -> CaseClause inp out ('CaseClauseParam ctor x) (//->) _ = CaseClause infixr 8 //->@@ -483,7 +512,7 @@    gInstrCase     :: GIsoValue x-    => Rec (CaseClause inp out) (GCaseClauses x) -> Instr (GValueType x ': inp) out+    => Rec (CaseClause inp out) (GCaseClauses x) -> RemFail Instr (GValueType x ': inp) out  instance GInstrCase x => GInstrCase (G.D1 i x) where   type GCaseClauses (G.D1 i x) = GCaseClauses x@@ -494,9 +523,7 @@   type GCaseClauses (x :+: y) = GCaseClauses x ++ GCaseClauses y   gInstrCase clauses =     let (leftClauses, rightClauses) = rsplit clauses-        lbranch = gInstrCase @x leftClauses-        rbranch = gInstrCase @y rightClauses-    in IF_LEFT lbranch rbranch+    in rfMerge IF_LEFT (gInstrCase @x leftClauses) (gInstrCase @y rightClauses)  instance GInstrCaseBranch ctor x => GInstrCase (G.C1 ('G.MetaCons ctor _1 _2) x) where   type GCaseClauses (G.C1 ('G.MetaCons ctor _1 _2) x) = '[GCaseBranchInput ctor x]@@ -510,7 +537,7 @@    gInstrCaseBranch     :: CaseClause inp out (GCaseBranchInput ctor x)-    -> Instr (GValueType x ': inp) out+    -> RemFail Instr (GValueType x ': inp) out  instance   ( GIsoValue x, GIsoValue y@@ -531,35 +558,35 @@  instance GInstrCaseBranch ctor G.U1 where   type GCaseBranchInput ctor G.U1 = 'CaseClauseParam ctor 'NoFields-  gInstrCaseBranch (CaseClause i) = DROP `Seq` i+  gInstrCaseBranch (CaseClause i) = rfMapAnyInstr (DROP `Seq`) i  -- Examples ---------------------------------------------------------------------------- -_caseMyType :: Instr (ToT MyType ': s) (ToT Integer ': s)+_caseMyType :: RemFail Instr (ToT MyType ': s) (ToT Integer ': s) _caseMyType = instrCase @MyType $-     #cMyCtor //-> Nop-  :& #cComplexThing //-> (DROP `Seq` PUSH (toVal @Integer 5))-  :& #cUselessThing //-> (DROP `Seq` PUSH (toVal @Integer 0))+     #cMyCtor //-> RfNormal Nop+  :& #cComplexThing //-> RfNormal (DROP `Seq` PUSH (toVal @Integer 5))+  :& #cUselessThing //-> RfNormal (DROP `Seq` PUSH (toVal @Integer 0))   :& RNil  -- Another version, written via tuple.-_caseMyType2 :: Instr (ToT MyType ': s) (ToT Integer ': s)+_caseMyType2 :: RemFail Instr (ToT MyType ': s) (ToT Integer ': s) _caseMyType2 = instrCase @MyType $ recFromTuple   ( #cMyCtor //->-      Nop+      RfNormal Nop   , #cComplexThing //->-      (DROP `Seq` PUSH (toVal @Integer 5))+      RfNormal (DROP `Seq` PUSH (toVal @Integer 5))   , #cUselessThing //->-      (DROP `Seq` PUSH (toVal @Integer 0))+      RfNormal (DROP `Seq` PUSH (toVal @Integer 0))   ) -_caseMyEnum :: Instr (ToT MyEnum ': ToT Integer ': s) (ToT Integer ': s)+_caseMyEnum :: RemFail Instr (ToT MyEnum ': ToT Integer ': s) (ToT Integer ': s) _caseMyEnum = instrCase @MyEnum $ recFromTuple-  ( #cCase1 //-> (DROP `Seq` PUSH (toVal @Integer 1))-  , #cCase2 //-> (DROP `Seq` PUSH (toVal @Integer 2))-  , #cCaseN //-> (DIP DROP `Seq` Nop)-  , #cCaseDef //-> Nop+  ( #cCase1 //-> RfNormal (DROP `Seq` PUSH (toVal @Integer 1))+  , #cCase2 //-> RfNormal (DROP `Seq` PUSH (toVal @Integer 2))+  , #cCaseN //-> RfNormal (DIP DROP `Seq` Nop)+  , #cCaseDef //-> RfNormal Nop   )  ----------------------------------------------------------------------------@@ -648,9 +675,11 @@  -- | Failure indicating that we expected value created with one constructor, -- but got value with different one.+-- The error message is intentionally ugly to keep it relatively short and+-- save on gas. failWithWrongCtor :: Instr i o failWithWrongCtor =-  PUSH (toVal [mt|unwrapUnsafe: unexpected constructor|]) `Seq`+  PUSH (toVal [mt|BadCtor|]) `Seq`   FAILWITH  -- Examples
+ src/Michelson/Typed/Haskell/LooseSum.hs view
@@ -0,0 +1,127 @@+{-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++-- | Representation of Haskell sum types via loosy typed Michelson values,+-- useful for e.g. errors and enums.+--+-- In particular, ADT sum can be represented as constructor name + data+-- it carries. Such expression does not have particular type because+-- different constructors may carry different data, and we avoid lifting+-- this data to a union in order to keep only the significant parts+-- (and thus not to confuse the client).+module Michelson.Typed.Haskell.LooseSum+  ( ComposeResult (..)+  , fromTaggedVal+  , toTaggedVal+  , LooseSumC+  ) where++import qualified Data.Kind as Kind+import Data.Singletons (SingI)+import Data.Typeable (TypeRep, Typeable, cast, typeRep)+import GHC.Generics ((:*:), (:+:))+import qualified GHC.Generics as G++import Michelson.Typed.Aliases+import Michelson.Typed.Haskell.Value+import Michelson.Typed.T+import Michelson.Typed.Value+import Util.TypeLits++-- | Possible outcomes of an attempt to construct a Haskell ADT value+-- from constructor name and relevant data.+data ComposeResult a+  = ComposeOk a+    -- ^ Composed fine.+  | ComposeCtorNotFound+    -- ^ No constructor with such name.+  | ComposeFieldTypeMismatch TypeRep TypeRep+    -- ^ Found required constructor, but type of data does not correspond+    -- to provided one.+  deriving stock (Functor)++instance Semigroup (ComposeResult a) where+  r@(ComposeOk _) <> _ = r+  _ <> r@(ComposeOk _) = r+  r@(ComposeFieldTypeMismatch _ _) <> _ = r+  _ <> r@(ComposeFieldTypeMismatch _ _) = r+  r@ComposeCtorNotFound <> ComposeCtorNotFound = r++instance Monoid (ComposeResult a) where+  mempty = ComposeCtorNotFound+  mappend = (<>)++-- | Constraint for 'hsDecompose' and 'hsCompose'.+type LooseSumC dt =+  ( Generic dt, GLooseSum (G.Rep dt)+  )++-- | Decompose Haskell type into constructor name and+-- data it carries, converting the latter into Michelson 'Value'.+toTaggedVal :: LooseSumC dt => dt -> (Text, SomeValue)+toTaggedVal = gHsDecompose . G.from++-- | Inverse to 'toTaggedVal'.+fromTaggedVal :: LooseSumC dt => (Text, SomeValue) -> ComposeResult dt+fromTaggedVal = fmap G.to . gHsCompose++-- | Generic traversal for 'hsCompose' and 'hsDecompose'.+class GLooseSum (x :: Kind.Type -> Kind.Type) where+  gHsDecompose :: x p -> (Text, SomeValue)+  gHsCompose :: (Text, SomeValue) -> ComposeResult (x p)++instance GLooseSum x => GLooseSum (G.D1 i x) where+  gHsDecompose = gHsDecompose . G.unM1+  gHsCompose = fmap G.M1 . gHsCompose++instance (GLooseSum x, GLooseSum y) => GLooseSum (x :+: y) where+  gHsDecompose = \case+    G.L1 x -> gHsDecompose x+    G.R1 y -> gHsDecompose y+  gHsCompose v = mconcat+    [ G.L1 <$> gHsCompose v+    , G.R1 <$> gHsCompose v+    ]++instance (GAccessField x, KnownSymbol ctor) =>+         GLooseSum (G.C1 ('G.MetaCons ctor f o) x) where+  gHsDecompose = (symbolValT' @ctor, ) . gExtractField @x . G.unM1+  gHsCompose (ctor, val)+    | symbolValT' @ctor == ctor = G.M1 <$> gMakeField @x val+    | otherwise = ComposeCtorNotFound++instance GLooseSum G.V1 where+  gHsDecompose = \case{}+  gHsCompose _ = mempty++-- | Pick a field from constructor with zero or one fields.+class GAccessField (x :: Kind.Type -> Kind.Type) where+  gExtractField :: x p -> SomeValue+  gMakeField :: SomeValue -> ComposeResult (x p)++instance GAccessField x => GAccessField (G.S1 i x) where+  gExtractField = gExtractField . G.unM1+  gMakeField v = G.M1 <$> gMakeField @x v++instance (Typeable a, IsoValue a, Typeable (ToT a), SingI (ToT a)) =>+         GAccessField (G.Rec0 a) where+  gExtractField = SomeValue . toVal . G.unK1+  gMakeField (SomeValue v) = G.K1 . fromVal <$> composeCast v++instance GAccessField G.U1 where+  gExtractField G.U1 = SomeValue $ toVal ()+  gMakeField (SomeValue v) = G.U1 <$ composeCast @_ @'TUnit v++composeCast :: forall a b. (Typeable a, Typeable b) => Value a -> ComposeResult (Value b)+composeCast a =+  case cast a of+    Nothing -> ComposeFieldTypeMismatch (typeRep (Proxy @a)) (typeRep (Proxy @b))+    Just b -> ComposeOk b++instance+  TypeError ('Text "Cannot compose/decompose constructors with more \+             \than one field" ':$$:+             'Text "Consider using tuple instead") =>+  GAccessField (x :*: y) where+  gExtractField = error "impossible"+  gMakeField = error "impossible"
src/Michelson/Typed/Haskell/Value.hs view
@@ -2,35 +2,57 @@  -- | Conversions between haskell types/values and Michelson ones. module Michelson.Typed.Haskell.Value-  ( IsoCValue (..)+  ( -- * Value conversions+    IsoCValue (..)   , IsoValue (..)   , GIsoValue (GValueType)-  , ToTs   , ToT'-  , ToTs'+  , SomeIsoValue (..)+  , AnyIsoValue (..)   , IsComparable+  , IsGenericIsoValue -  , ContractAddr (..)+    -- * Missing Haskell analogies to Michelson values+  , EntryPointCall+  , SomeEntryPointCall+  , ContractRef (..)+  , coerceContractRef   , BigMap (..)++    -- * Stack conversion+  , ToTs+  , ToTs'+  , IsoValuesStack (..)+  , totsKnownLemma+  , totsAppendLemma   ) where +import Data.Default (Default (..)) import qualified Data.Kind as Kind-import Data.Default (Default)+import Data.Constraint (Dict (..), (:-)(..)) import qualified Data.Map.Strict as Map import qualified Data.Set as Set+import Data.Vinyl.Core (Rec(..))+import Fmt (Buildable(..)) import GHC.Generics ((:*:)(..), (:+:)(..)) import qualified GHC.Generics as G import Named (NamedF(..)) +import Michelson.Text import Michelson.Typed.Aliases import Michelson.Typed.CValue+import Michelson.Typed.EntryPoints import Michelson.Typed.T-import Michelson.Text import Michelson.Typed.Value import Tezos.Address (Address)-import Tezos.Core (Mutez, Timestamp)+import Tezos.Core (Mutez, Timestamp, ChainId) import Tezos.Crypto (KeyHash, PublicKey, Signature)+import Util.Type +----------------------------------------------------------------------------+-- Comparable values isomorphism+----------------------------------------------------------------------------+ -- | Isomorphism between Michelson primitive values and plain Haskell types. class IsoCValue a where   -- | Type function that converts a regular Haskell type into a comparable type@@ -78,8 +100,18 @@   toCVal = CvMutez   fromCVal (CvMutez m) = m +-- | This instance erases reference to contract entrypoint!+-- If this is an issue, use `EpAddress` instead.+--+-- Applications which use addresses just as participants identifiers+-- should not experience problems with using plain 'Address'. instance IsoCValue Address where   type ToCT Address = 'CAddress+  toCVal addr = CvAddress $ EpAddress addr def+  fromCVal (CvAddress a) = eaAddress a++instance IsoCValue EpAddress where+  type ToCT EpAddress = 'CAddress   toCVal = CvAddress   fromCVal (CvAddress a) = a @@ -93,6 +125,10 @@   toCVal = CvTimestamp   fromCVal (CvTimestamp t) = t +----------------------------------------------------------------------------+-- Complex values isomorphism+----------------------------------------------------------------------------+ -- | Isomorphism between Michelson values and plain Haskell types. -- -- Default implementation of this typeclass converts ADTs to Michelson@@ -116,24 +152,24 @@     => Value (ToT a) -> a   fromVal = G.to . gFromValue --- | Type function to convert a Haskell stack type to @T@-based one.-type family ToTs (ts :: [Kind.Type]) :: [T] where-  ToTs '[] = '[]-  ToTs (x ': xs) = ToT x ': ToTs xs- -- | Overloaded version of 'ToT' to work on Haskell and @T@ types. type family ToT' (t :: k) :: T where   ToT' (t :: T) = t   ToT' (t :: Kind.Type) = ToT t --- | Overloaded version of 'ToTs' to work on Haskell and @T@ stacks.-type family ToTs' (t :: [k]) :: [T] where-  ToTs' (t :: [T]) = t-  ToTs' (a :: [Kind.Type]) = ToTs a+-- | Hides some Haskell value put in line with Michelson 'Value'.+data SomeIsoValue where+  SomeIsoValue :: (Typeable a, IsoValue a) => a -> SomeIsoValue +-- | Any Haskell value which can be converted to Michelson 'Value'.+newtype AnyIsoValue = AnyIsoValue (forall a. IsoValue a => a)+ -- | A useful property which holds for all 'CT' types. type IsComparable c = ToT c ~ 'Tc (ToCT c) +-- Instances+----------------------------------------------------------------------------+ instance IsoValue Integer where   type ToT Integer = 'Tc (ToCT Integer)   toVal = VC . toCVal@@ -184,6 +220,11 @@   toVal = VC . toCVal   fromVal (VC x) = fromCVal x +instance IsoValue EpAddress where+  type ToT EpAddress = 'Tc (ToCT EpAddress)+  toVal = VC . toCVal+  fromVal (VC x) = fromCVal x+ instance IsoValue PublicKey where   type ToT PublicKey = 'TKey   toVal = VKey@@ -194,6 +235,11 @@   toVal = VSignature   fromVal (VSignature x) = x +instance IsoValue ChainId where+  type ToT ChainId = 'TChainId+  toVal = VChainId+  fromVal (VChainId x) = x+ instance IsoValue ()  instance IsoValue a => IsoValue [a] where@@ -245,16 +291,29 @@ -- Types used specifically for conversion ---------------------------------------------------------------------------- +type EntryPointCall param arg = EntryPointCallT (ToT param) (ToT arg)++type SomeEntryPointCall arg = SomeEntryPointCallT (ToT arg)+ -- | Since @Contract@ name is used to designate contract code, lets call -- analogy of 'TContract' type as follows.-newtype ContractAddr (cp :: Kind.Type) =-  ContractAddr { unContractAddress :: Address }+data ContractRef (arg :: Kind.Type) = ContractRef+  { crAddress :: Address+  , crEntryPoint :: SomeEntryPointCall arg+  } deriving stock (Eq, Show) -instance IsoValue (ContractAddr cp) where-  type ToT (ContractAddr cp) = 'TContract (ToT cp)-  toVal = VContract . unContractAddress-  fromVal (VContract a) = ContractAddr a+instance Buildable (ContractRef arg) where+  build = buildVContract . toVal +instance IsoValue (ContractRef arg) where+  type ToT (ContractRef arg) = 'TContract (ToT arg)+  toVal ContractRef{..} = VContract crAddress crEntryPoint+  fromVal (VContract addr epc) = ContractRef addr epc++-- | Replace type argument of 'ContractAddr' with isomorphic one.+coerceContractRef :: (ToT a ~ ToT b) => ContractRef a -> ContractRef b+coerceContractRef ContractRef{..} = ContractRef{..}+ newtype BigMap k v = BigMap { unBigMap :: Map k v }   deriving stock (Eq, Show)   deriving newtype (Default, Semigroup, Monoid)@@ -308,3 +367,49 @@   type GValueType (G.Rec0 a) = ToT a   gToValue = toVal . G.unK1   gFromValue = G.K1 . fromVal++-- | Whether Michelson representation of the type is derived via Generics.+type IsGenericIsoValue t =+  (IsoValue t, Generic t, ToT t ~ GValueType (G.Rep t))++----------------------------------------------------------------------------+-- Stacks conversion+----------------------------------------------------------------------------++-- | Type function to convert a Haskell stack type to @T@-based one.+type family ToTs (ts :: [Kind.Type]) :: [T] where+  ToTs '[] = '[]+  ToTs (x ': xs) = ToT x ': ToTs xs++-- | Overloaded version of 'ToTs' to work on Haskell and @T@ stacks.+type family ToTs' (t :: [k]) :: [T] where+  ToTs' (t :: [T]) = t+  ToTs' (a :: [Kind.Type]) = ToTs a++-- | Isomorphism between Michelson stack and its Haskell reflection.+class IsoValuesStack (ts :: [Kind.Type]) where+  toValStack :: Rec Identity ts -> Rec Value (ToTs ts)+  fromValStack :: Rec Value (ToTs ts) -> Rec Identity ts++instance IsoValuesStack '[] where+  toValStack RNil = RNil+  fromValStack RNil = RNil++instance (IsoValue t, IsoValuesStack st) => IsoValuesStack (t ': st) where+  toValStack (v :& vs) = toVal v :& toValStack vs+  fromValStack (v :& vs) = fromVal v :& fromValStack vs++totsKnownLemma :: forall s. KnownList s :- KnownList (ToTs s)+totsKnownLemma = Sub $ case klist @s of+  KNil -> Dict+  KCons _ (_ :: Proxy a') ->+    case totsKnownLemma @a' of Sub Dict -> Dict++totsAppendLemma+  :: forall a b.+      (KnownList a)+  => Dict (ToTs (a ++ b) ~ (ToTs a ++ ToTs b))+totsAppendLemma = case klist @a of+  KNil -> Dict+  KCons _ (_ :: Proxy a') ->+    case totsAppendLemma @a' @b of Dict -> Dict
src/Michelson/Typed/Instr.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE QuantifiedConstraints #-}  -- | Module, containing data types for Michelson value. @@ -10,20 +11,77 @@   , PrintComment (..)   , TestAssert (..)   , Contract+  , FullContract (..)+  , fcParamNotes+  , mapFullContractCode+  , pattern CAR+  , pattern CDR+  , PackedNotes(..)+  , ConstraintDIPN+  , ConstraintDIPN'+  , ConstraintDIG+  , ConstraintDIG'+  , ConstraintDUG+  , ConstraintDUG'   ) where  import Data.Singletons (SingI(..)) import Fmt ((+||), (||+))+import qualified GHC.TypeNats as GHC (Nat) import qualified Text.Show -import Michelson.Typed.Annotation (Notes)+import Michelson.Typed.Annotation (Notes(..)) import Michelson.Typed.Arith+import Michelson.Doc+import Michelson.Typed.EntryPoints import Michelson.Typed.Polymorphic import Michelson.Typed.Scope import Michelson.Typed.T (CT(..), T(..)) import Michelson.Typed.Value (ContractInp, ContractOut, Value'(..))+import Michelson.Untyped (Annotation(..), FieldAnn) import Util.Peano+import Util.Type (type (++), KnownList) +-- | A wrapper to wrap annotations and corresponding singleton.+-- Apart from packing notes along with the corresponding Singleton,+-- this wrapper type, when included with `Instr` also helps to derive+-- the `Show` instance for `Instr` as `Sing a` does not have a `Show`+-- instance on its own.+data PackedNotes a where+  PackedNotes :: Notes a -> Sing a -> PackedNotes (a ': s)++instance Show (PackedNotes a) where+  show (PackedNotes n _) = show n++-- | Constraint that is used in DIPN, we want to share it with+-- typechecking code and eDSL code.+type ConstraintDIPN' kind (n :: Peano) (inp :: [kind])+  (out :: [kind]) (s :: [kind]) (s' :: [kind]) =+  ( SingI n, KnownPeano n, RequireLongerOrSameLength inp n+  , ((Take n inp) ++ s) ~ inp+  , ((Take n inp) ++ s') ~ out+  )++type ConstraintDIPN n inp out s s' = ConstraintDIPN' T n inp out s s'++type ConstraintDIG' kind (n :: Peano) (inp :: [kind])+  (out :: [kind]) (a :: kind) =+  ( SingI n, KnownPeano n, RequireLongerThan inp n+  , inp ~ (Take n inp ++ (a ': Drop ('S n) inp))+  , out ~ (a ': Take n inp ++ Drop ('S n) inp)+  )++type ConstraintDIG n inp out a = ConstraintDIG' T n inp out a++type ConstraintDUG' kind (n :: Peano) (inp :: [kind])+  (out :: [kind]) (a :: kind) =+  ( SingI n, KnownPeano n, RequireLongerThan out n+  , inp ~ (a ': Drop ('S 'Z) inp)+  , out ~ (Take n (Drop ('S 'Z) inp) ++ (a ': Drop ('S n) inp))+  )++type ConstraintDUG n inp out a = ConstraintDUG' T n inp out a+ -- | Representation of Michelson instruction or sequence -- of instructions. --@@ -41,6 +99,39 @@ -- Type parameter @out@ states for output stack type or type -- of stack that will be left after instruction's execution. data Instr (inp :: [T]) (out :: [T]) where+  -- | A wrapper for instruction that also contain annotations for the+  -- top type on the result stack.+  --+  -- As of now, when converting from untyped representation,+  -- we only preserve field annotations and type annotations.+  -- Variable annotations are not preserved.+  --+  -- This can wrap only instructions with at least one non-failing execution+  -- branch.+  InstrWithNotes :: PackedNotes b -> Instr a b -> Instr a b++  -- | Execute given instruction on truncated stack.+  --+  -- This can wrap only instructions with at least one non-failing execution+  -- branch.+  --+  -- Morley has no such instruction, it is used solely in eDSLs.+  -- This instruction is sound because for all Michelson instructions+  -- the following property holds: if some code accepts stack @i@ and+  -- produces stack @o@, when it can also be run on stack @i + s@+  -- producing stack @o + s@; and also because Michelson never makes+  -- implicit assumptions on types, rather you have to express all+  -- "yet ambiguous" type information in code.+  -- We could make this not an instruction but rather a function+  -- which modifies an instruction (this would also automatically prove+  -- soundness of used transformation), but it occured to be tricky+  -- (in particular for TestAssert and DipN and family), so let's leave+  -- this for future work.+  FrameInstr+    :: forall a b s.+       (KnownList a, KnownList b)+    => Proxy s -> Instr a b -> Instr (a ++ s) (b ++ s)+   Seq :: Instr a b -> Instr b c -> Instr a c   -- | Nop operation. Missing in Michelson spec, added to parse construction   -- like  `IF {} { SWAP; DROP; }`.@@ -50,12 +141,34 @@   -- It is crucial because serialisation of a contract   -- depends on precise structure of its code.   Nested :: Instr inp out -> Instr inp out+  -- | Places documentation generated for given instruction under some group.+  -- This is not part of 'ExtInstr' because it does not behave like 'Nop';+  -- instead, it inherits behaviour of instruction put within it.+  DocGroup :: DocGrouping -> Instr inp out -> Instr inp out +  -- | Variants of CAR/CDR to retain field annotations as they relate to the input+  -- stack, and hence won't be available from the annotation notes from+  -- the result stack we pack with the instructions during type check.+  AnnCAR :: FieldAnn -> Instr ('TPair a b ': s) (a ': s)+  AnnCDR :: FieldAnn -> Instr ('TPair a b ': s) (b ': s)++  -- Note that we can not merge DROP and DROPN into one instruction+  -- because they are packed differently.   DROP :: Instr (a ': s) s+  DROPN+    :: forall (n :: Peano) s.+    (SingI n, KnownPeano n, RequireLongerOrSameLength s n)+    => Sing n -> Instr s (Drop n s)   DUP  :: Instr (a ': s) (a ': a ': s)   SWAP :: Instr (a ': b ': s) (b ': a ': s)+  DIG+    :: forall (n :: Peano) inp out a. ConstraintDIG n inp out a+    => Sing n -> Instr inp out+  DUG+    :: forall (n :: Peano) inp out a. ConstraintDUG n inp out a+    => Sing n -> Instr inp out   PUSH-    :: forall t s . (SingI t, HasNoOp t, HasNoBigMap t)+    :: forall t s . ConstantScope t     => Value' Instr t -> Instr s (t ': s)   SOME :: Instr (a ': s) ('TOption a ': s)   NONE :: forall a s . SingI a => Instr s ('TOption a ': s)@@ -65,8 +178,6 @@     -> Instr (a ': s) s'     -> Instr ('TOption a ': s) s'   PAIR :: Instr (a ': b ': s) ('TPair a b ': s)-  CAR :: Instr ('TPair a b ': s) (a ': s)-  CDR :: Instr ('TPair a b ': s) (b ': s)   LEFT :: forall b a s . SingI b => Instr (a ': s) ('TOr a b ': s)   RIGHT :: forall a b s . SingI a => Instr (b ': s) ('TOr a b ': s)   IF_LEFT@@ -82,6 +193,7 @@   SIZE :: SizeOp c => Instr (c ': s) ('Tc 'CNat ': s)   EMPTY_SET :: (Typeable e, SingI e) => Instr s ('TSet e ': s)   EMPTY_MAP :: (Typeable a, Typeable b, SingI a, SingI b) => Instr s ('TMap a b ': s)+  EMPTY_BIG_MAP :: (Typeable a, Typeable b, SingI a, SingI b) => Instr s ('TBigMap a b ': s)   MAP :: MapOp c       => Instr (MapOpInp c ': s) (b ': s)       -> Instr (c ': s) (MapOpRes c b ': s)@@ -104,12 +216,18 @@   LAMBDA :: forall i o s . (Each [Typeable, SingI] [i, o])          => Value' Instr ('TLambda i o) -> Instr s ('TLambda i o ': s)   EXEC :: Instr (t1 ': 'TLambda t1 t2 ': s) (t2 ': s)+  APPLY+    :: forall a b c s . ConstantScope a+    => Instr (a ': 'TLambda ('TPair a b) c ': s) ('TLambda b c ': s)   DIP :: Instr a c -> Instr (b ': a) (b ': c)+  DIPN+    :: forall (n :: Peano) inp out s s'. ConstraintDIPN n inp out s s'+    => Sing n -> Instr s s' -> Instr inp out   FAILWITH :: (Typeable a, SingI a) => Instr (a ': s) t   CAST :: forall a s . SingI a => Instr (a ': s) (a ': s)   RENAME :: Instr (a ': s) (a ': s)-  PACK :: (SingI a, HasNoOp a, HasNoBigMap a) => Instr (a ': s) ('Tc 'CBytes ': s)-  UNPACK :: (SingI a, HasNoOp a, HasNoBigMap a) => Instr ('Tc 'CBytes ': s) ('TOption a ': s)+  PACK :: PackedValScope a => Instr (a ': s) ('Tc 'CBytes ': s)+  UNPACK :: UnpackedValScope a => Instr ('Tc 'CBytes ': s) ('TOption a ': s)   CONCAT :: ConcatOp c => Instr (c ': c ': s) (c ': s)   CONCAT' :: ConcatOp c => Instr ('TList c ': s) (c ': s)   SLICE@@ -155,8 +273,8 @@     :: UnaryArithOp Not n     => Instr ('Tc n ': s) ('Tc (UnaryArithRes Not n) ': s)   COMPARE-    :: (ArithOp Compare n m, Typeable n, Typeable m)-    => Instr ('Tc n ': 'Tc m ': s) ('Tc (ArithRes Compare n m) ': s)+    :: (ArithOp Compare n n, Typeable n)+    => Instr ('Tc n ': 'Tc n ': s) ('Tc (ArithRes Compare n n) ': s)   EQ     :: UnaryArithOp Eq' n     => Instr ('Tc n ': s) ('Tc (UnaryArithRes Eq' n) ': s)@@ -176,33 +294,30 @@     :: UnaryArithOp Ge n     => Instr ('Tc n ': s) ('Tc (UnaryArithRes Ge n) ': s)   INT :: Instr ('Tc 'CNat ': s) ('Tc 'CInt ': s)-  SELF :: forall (cp :: T) s . Instr s ('TContract cp ': s)+  -- TODO [TM-280]: SELF should now be able to refer to specific entrypoint+  SELF+    :: forall (p :: T) s .+       (ParameterScope p)+    => Instr s ('TContract p ': s)   CONTRACT-    :: (SingI p, Typeable p) => Notes p -> Instr ('Tc 'CAddress ': s) ('TOption ('TContract p) ': s)-  -- Store Notes to be able to verify CONTRACT in typechecker+    :: (ParameterScope p)+    => Notes p   -- Store Notes to be able to verify CONTRACT in typechecker+    -> EpName+    -> Instr ('Tc 'CAddress ': s) ('TOption ('TContract p) ': s)   TRANSFER_TOKENS-    :: (Typeable p, SingI p, HasNoOp p, HasNoBigMap p) =>+    :: (ParameterScope p) =>        Instr (p ': 'Tc 'CMutez ': 'TContract p ': s)                    ('TOperation ': s)   SET_DELEGATE     :: Instr ('TOption ('Tc 'CKeyHash) ': s) ('TOperation ': s) -  CREATE_ACCOUNT-    :: Instr-        ('Tc 'CKeyHash ': 'TOption ('Tc 'CKeyHash) ': 'Tc 'CBool-         ': 'Tc 'CMutez ': s) ('TOperation ': 'Tc 'CAddress ': s)-   CREATE_CONTRACT-    :: (Each [Typeable, SingI, HasNoOp] [p, g], HasNoBigMap p, BigMapConstraint g)-    => Instr '[ 'TPair p g ] '[ 'TPair ('TList 'TOperation) g ]-    -> Instr ('Tc 'CKeyHash ':-              'TOption ('Tc 'CKeyHash) ':-              'Tc 'CBool ':-              'Tc 'CBool ':+    :: (ParameterScope p, StorageScope g)+    => FullContract p g+    -> Instr ('TOption ('Tc 'CKeyHash) ':               'Tc 'CMutez ':                g ': s)              ('TOperation ': 'Tc 'CAddress ': s)-   IMPLICIT_ACCOUNT     :: Instr ('Tc 'CKeyHash ': s) ('TContract 'TUnit ': s)   NOW :: Instr s ('Tc 'CTimestamp ': s)@@ -219,11 +334,28 @@   SOURCE :: Instr s ('Tc 'CAddress ': s)   SENDER :: Instr s ('Tc 'CAddress ': s)   ADDRESS :: Instr ('TContract a ': s) ('Tc 'CAddress ': s)+  CHAIN_ID :: Instr s ('TChainId ': s)  deriving instance Show (Instr inp out) ----------------------------------------------------+instance Semigroup (Instr s s) where+  (<>) = Seq+instance Monoid (Instr s s) where+  mempty = Nop +instance NFData (Instr inp out) where+  -- This is the simplest way, and we don't care much about performance in tests.+  -- May be unsatisfactory for benchmarks though.+  -- If @instance Show@ is not automatically derived anymore, or you have other+  -- problems with this instance, then please reimplement it manually.+  rnf = rnf @String . show++pattern CAR :: Instr ('TPair a b : s) (a : s)+pattern CAR = AnnCAR (Annotation "")++pattern CDR :: Instr ('TPair a b : s) (b: s)+pattern CDR = AnnCDR (Annotation "")+ data TestAssert (s :: [T]) where   TestAssert     :: (Typeable out)@@ -238,7 +370,7 @@ data StackRef (st :: [T]) where   -- | Keeps 0-based index to a stack element counting from the top.   StackRef-    :: (KnownPeano idx, LongerThan st idx)+    :: (KnownPeano idx, SingI idx, RequireLongerThan st idx)     => Sing (idx :: Peano) -> StackRef st  instance Eq (StackRef st) where@@ -249,10 +381,10 @@  -- | Create a stack reference, performing checks at compile time. mkStackRef-  :: forall (gn :: Nat) st n.+  :: forall (gn :: GHC.Nat) st n.       (n ~ ToPeano gn, SingI n, KnownPeano n, RequireLongerThan st n)   => StackRef st-mkStackRef = requiredLongerThan @st @n $ StackRef $ sing @(ToPeano gn)+mkStackRef = StackRef $ sing @(ToPeano gn)  -- | A print format with references into the stack newtype PrintComment (st :: [T]) = PrintComment@@ -266,8 +398,29 @@ data ExtInstr s   = TEST_ASSERT (TestAssert s)   | PRINT (PrintComment s)+  | DOC_ITEM SomeDocItem   deriving (Show)  ---------------------------------------------------  type Contract cp st = Instr (ContractInp cp st) (ContractOut st)++-- | Typed contract and information about annotations+-- which is not present in the contract code.+-- TODO [#12]: rename this to 'Contract' and the current 'Contract' to 'ContractCode'?+data FullContract cp st = (ParameterScope cp, StorageScope st) => FullContract+  { fcCode :: Contract cp st+  , fcParamNotesSafe :: ParamNotes cp+  , fcStoreNotes :: Notes st+  }++deriving instance Show (FullContract cp st)++fcParamNotes :: FullContract cp st -> Notes cp+fcParamNotes = unParamNotes . fcParamNotesSafe++mapFullContractCode+  :: (Contract cp st -> Contract cp st)+  -> FullContract cp st+  -> FullContract cp st+mapFullContractCode f contract = contract { fcCode = f $ fcCode contract }
− src/Michelson/Typed/Print.hs
@@ -1,21 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}---- | Types printing.------ Moved in a separate module, because we print via converting to--- untyped @T@ type to avoid duplication.-module Michelson.Typed.Print-  ( buildStack-  ) where--import Fmt (Buildable(..), Builder, listF)--import Michelson.Typed.Extract-import Michelson.Typed.T--instance Buildable T where-  build = build . toUType---- | Format type stack in a pretty way.-buildStack :: [T] -> Builder-buildStack = listF
src/Michelson/Typed/Scope.hs view
@@ -1,34 +1,108 @@+{-# LANGUAGE UndecidableSuperClasses #-} {-# OPTIONS_GHC -Wno-redundant-constraints #-} --- | Module, containing restrictions imposed by instruction or value scope.+{- | Module, containing restrictions imposed by instruction or value scope. +Michelson have multiple restrictions on values, examples:+* @operation@ type cannot appear in parameter.+* @big_map@ type cannot appear in @PUSH@-able constants.+* @contract@ type cannot appear in type we @UNPACK@ to.++Thus we declare multiple "scopes" - constraints applied in corresponding+situations, for instance+* 'ParameterScope';+* 'StorageScope';+* 'ConstantScope'.++Also we separate multiple "classes" of scope-related constraints.++* 'ParameterScope' and similar ones are used within Michelson engine,+they are understandable by GHC but produce not very clarifying errors.++* 'ProperParameterBetterErrors' and similar ones are middle-layer constraints,+they produce human-readable errors but GHC cannot make conclusions from them.+They are supposed to be used only by eDSLs to define their own high-level+constraints.++* Lorentz and other eDSLs may declare their own constraints, in most cases+you should use them. For example see 'Lorentz.Constraints' module.++-}+ module Michelson.Typed.Scope-  ( AllowBigMap+  ( -- * Scopes+    ParameterScope+  , StorageScope+  , ConstantScope+  , PackedValScope+  , UnpackedValScope+  , PrintedValScope++  , ProperParameterBetterErrors+  , ProperStorageBetterErrors+  , ProperConstantBetterErrors+  , ProperPackedValBetterErrors+  , ProperUnpackedValBetterErrors+  , ProperPrintedValBetterErrors++  , properParameterEvi+  , properStorageEvi+  , properConstantEvi+  , properPackedValEvi+  , properUnpackedValEvi+  , properPrintedValEvi+  , (:-)(..)++    -- * Implementation internals   , HasNoBigMap+  , HasNoNestedBigMaps   , HasNoOp-  , ForbidBigMap+  , HasNoContract+  , ContainsBigMap+  , ContainsNestedBigMaps+   , ForbidOp-  , BigMapPresence (..)+  , ForbidContract+  , ForbidBigMap+  , ForbidNestedBigMaps+  , FailOnBigMapFound+  , FailOnNestedBigMapsFound+  , FailOnOperationFound+   , OpPresence (..)-  , BigMapConstraint+  , ContractPresence (..)+  , BigMapPresence (..)+  , NestedBigMapsPresence (..)   , checkOpPresence+  , checkContractTypePresence   , checkBigMapPresence-  , checkBigMapConstraint+  , checkNestedBigMapsPresence   , opAbsense+  , contractTypeAbsense   , bigMapAbsense+  , nestedBigMapsAbsense   , forbiddenOp+  , forbiddenContractType   , forbiddenBigMap-  , bigMapConstrained+  , forbiddenNestedBigMaps++    -- * Re-exports+  , withDict   ) where -import Data.Constraint (Dict(..))+import Data.Constraint ((:-)(..), Dict(..), withDict, (\\))+import qualified Data.Constraint as C import Data.Singletons (SingI(..))-import Data.Type.Bool  (type (||))+import Data.Type.Bool (type (||)) import GHC.TypeLits (ErrorMessage(..), TypeError)  import Michelson.Typed.Sing (Sing(..)) import Michelson.Typed.T (T(..)) +----------------------------------------------------------------------------+-- Constraints+----------------------------------------------------------------------------+ -- | Whether this type contains 'TOperation' type. -- -- In some scopes (constants, parameters, storage) appearing for operation type@@ -39,6 +113,7 @@   ContainsOp 'TKey = 'False   ContainsOp 'TUnit = 'False   ContainsOp 'TSignature = 'False+  ContainsOp 'TChainId = 'False   ContainsOp ('TOption t) = ContainsOp t   ContainsOp ('TList t) = ContainsOp t   ContainsOp ('TSet _) = 'False@@ -50,16 +125,35 @@   ContainsOp ('TMap _ v) = ContainsOp v   ContainsOp ('TBigMap _ v) = ContainsOp v --- | Whether this type contains 'TBigMap' type.+-- | Whether this type contains 'TContract' type. ----- In some scopes (constants, parameters) appearing for big_map type--- is prohibited. It is permitted in toplevel left element of storage pair.--- Big_maps in input/output of lambdas are allowed without limits though.+-- In some scopes (constants, storage) appearing for contract type+-- is prohibited.+-- Contracts in input/output of lambdas are allowed without limits though.+type family ContainsContract (t :: T) :: Bool where+  ContainsContract ('Tc _) = 'False+  ContainsContract 'TKey = 'False+  ContainsContract 'TUnit = 'False+  ContainsContract 'TSignature = 'False+  ContainsContract 'TChainId = 'False+  ContainsContract ('TOption t) = ContainsContract t+  ContainsContract ('TList t) = ContainsContract t+  ContainsContract ('TSet _) = 'False+  ContainsContract 'TOperation = 'False+  ContainsContract ('TContract _) = 'True+  ContainsContract ('TPair a b) = ContainsContract a || ContainsContract b+  ContainsContract ('TOr a b) = ContainsContract a || ContainsContract b+  ContainsContract ('TLambda _ _) = 'False+  ContainsContract ('TMap _ v) = ContainsContract v+  ContainsContract ('TBigMap _ v) = ContainsContract v++-- | Whether this type contains 'TBigMap' type. type family ContainsBigMap (t :: T) :: Bool where   ContainsBigMap ('Tc _) = 'False   ContainsBigMap 'TKey = 'False   ContainsBigMap 'TUnit = 'False   ContainsBigMap 'TSignature = 'False+  ContainsBigMap 'TChainId = 'False   ContainsBigMap ('TOption t) = ContainsBigMap t   ContainsBigMap ('TList t) = ContainsBigMap t   ContainsBigMap ('TSet _) = 'False@@ -71,6 +165,28 @@   ContainsBigMap ('TMap _ v) = ContainsBigMap v   ContainsBigMap ('TBigMap _ _) = 'True +-- | Whether this type contains a type with nested 'TBigMap's .+--+-- Nested big_maps (i.e. big_map which contains another big_map inside of it's value type). Are+-- prohibited in all contexts. Some context such as PUSH, APPLY, PACK/UNPACK instructions are more+-- strict because they doesn't work with big_map at all.+type family ContainsNestedBigMaps (t :: T) :: Bool where+  ContainsNestedBigMaps ('Tc _) = 'False+  ContainsNestedBigMaps 'TKey = 'False+  ContainsNestedBigMaps 'TUnit = 'False+  ContainsNestedBigMaps 'TSignature = 'False+  ContainsNestedBigMaps 'TChainId = 'False+  ContainsNestedBigMaps ('TOption t) = ContainsNestedBigMaps t+  ContainsNestedBigMaps ('TList t) = ContainsNestedBigMaps t+  ContainsNestedBigMaps ('TSet _) = 'False+  ContainsNestedBigMaps 'TOperation = 'False+  ContainsNestedBigMaps ('TContract t) = ContainsNestedBigMaps t+  ContainsNestedBigMaps ('TPair a b) = ContainsNestedBigMaps a || ContainsNestedBigMaps b+  ContainsNestedBigMaps ('TOr a b) = ContainsNestedBigMaps a || ContainsNestedBigMaps b+  ContainsNestedBigMaps ('TLambda _ _) = 'False+  ContainsNestedBigMaps ('TMap _ v) = ContainsNestedBigMaps v+  ContainsNestedBigMaps ('TBigMap _ v) = ContainsBigMap v+ -- | Constraint which ensures that operation type does not appear in a given type. -- -- Not just a type alias in order to be able to partially apply it@@ -78,22 +194,17 @@ class (ContainsOp t ~ 'False) => HasNoOp t instance (ContainsOp t ~ 'False) => HasNoOp t +-- | Constraint which ensures that contract type does not appear in a given type.+class (ContainsContract t ~ 'False) => HasNoContract t+instance (ContainsContract t ~ 'False) => HasNoContract t+ -- | Constraint which ensures that bigmap does not appear in a given type. class (ContainsBigMap t ~ 'False) => HasNoBigMap t instance (ContainsBigMap t ~ 'False) => HasNoBigMap t --- | Type family to check if t is ill-typed contract storage---   (it contains bigmap not on the left of its toplevel pair)------ Used in @BigMapConstraint@-type family BadBigMapPair t :: Bool where-  BadBigMapPair ('TPair ('TBigMap _ v) b) =-    ContainsBigMap v || ContainsBigMap b-  BadBigMapPair t = ContainsBigMap t---- | Constraint which ensures, that @t@ can be used as type of contract storage---   so it optionally has bigmap only on the left of its toplevel pair-type BigMapConstraint t = BadBigMapPair t ~ 'False+-- | Constraint which ensures that there are no nested bigmaps+class (ContainsNestedBigMaps t ~ 'False) => HasNoNestedBigMaps t+instance (ContainsNestedBigMaps t ~ 'False) => HasNoNestedBigMaps t  -- | Report a human-readable error about 'TOperation' at a wrong place. type family FailOnOperationFound (enabled :: Bool) :: Constraint where@@ -101,66 +212,116 @@     TypeError ('Text "Operations are not allowed in this scope")   FailOnOperationFound 'False = () +-- | Report a human-readable error about 'TContract' at a wrong place.+type family FailOnContractFound (enabled :: Bool) :: Constraint where+  FailOnContractFound 'True =+    TypeError ('Text "Contracts are not allowed in this scope")+  FailOnContractFound 'False = ()+ -- | Report a human-readable error about 'TBigMap' at a wrong place. type family FailOnBigMapFound (enabled :: Bool) :: Constraint where   FailOnBigMapFound 'True =     TypeError ('Text "BigMaps are not allowed in this scope")   FailOnBigMapFound 'False = () +-- | Report a human-readable error that 'TBigMap' contains another 'TBigMap'+type family FailOnNestedBigMapsFound (enabled :: Bool) :: Constraint where+  FailOnNestedBigMapsFound 'True =+    TypeError ('Text "Nested BigMaps are not allowed")+  FailOnNestedBigMapsFound 'False = ()+ -- | This is like 'HasNoOp', it raises a more human-readable error--- when @t@ type is concrete, but you cannot easily extract a proof--- of no-operation-presence from it.+-- when @t@ type is concrete, but GHC cannot make any conclusions+-- from such constraint as it can for 'HasNoOp. -- -- Use it in our eDSL. type ForbidOp t = FailOnOperationFound (ContainsOp t) +type ForbidContract t = FailOnContractFound (ContainsContract t)+ type ForbidBigMap t = FailOnBigMapFound (ContainsBigMap t) -type AllowBigMap t = FailOnBigMapFound (BadBigMapPair t)+type ForbidNestedBigMaps t = FailOnNestedBigMapsFound (ContainsNestedBigMaps t) +-- | Evidence of that 'HasNoOp' is deducable from 'ForbidOp'.+forbiddenOpEvi :: forall t. (SingI t, ForbidOp t) :- HasNoOp t+forbiddenOpEvi = Sub $+  -- It's not clear now to proof GHC that @HasNoOp t@ is implication of+  -- @ForbidOp t@, so we use @error@ below and also disable+  -- "-Wredundant-constraints" extension.+  case checkOpPresence (sing @t) of+    OpAbsent -> Dict+    OpPresent -> error "impossible"+ -- | Reify 'HasNoOp' contraint from 'ForbidOp'.+--+-- Left for backward compatibility. forbiddenOp   :: forall t a.      (SingI t, ForbidOp t)   => (HasNoOp t => a)   -> a-forbiddenOp a =-  -- It's not clear now to proof GHC that @HasNoOp t@ is implication of-  -- @ForbidOp t@, so we use @error@ below and also disable-  -- "-Wredundant-constraints" extension.-  case checkOpPresence (sing @t) of-    OpAbsent -> a-    OpPresent -> error "impossible"+forbiddenOp = withDict $ forbiddenOpEvi @t +forbiddenBigMapEvi :: forall t. (SingI t, ForbidBigMap t) :- HasNoBigMap t+forbiddenBigMapEvi = Sub $+  case checkBigMapPresence (sing @t) of+    BigMapAbsent -> Dict+    BigMapPresent -> error "impossible"++forbiddenNestedBigMapsEvi :: forall t. (SingI t, ForbidNestedBigMaps t) :- HasNoNestedBigMaps t+forbiddenNestedBigMapsEvi = Sub $+  case checkNestedBigMapsPresence (sing @t) of+    NestedBigMapsAbsent -> Dict+    NestedBigMapsPresent -> error "impossible"+ forbiddenBigMap   :: forall t a.      (SingI t, ForbidBigMap t)   => (HasNoBigMap t => a)   -> a-forbiddenBigMap a =-  case checkBigMapPresence (sing @t) of-    BigMapAbsent -> a-    BigMapPresent -> error "impossible"+forbiddenBigMap = withDict $ forbiddenBigMapEvi @t -checkBigMapConstraint+forbiddenNestedBigMaps   :: forall t a.-     (SingI t, AllowBigMap t)-  => (BigMapConstraint t => a)+     (SingI t, ForbidNestedBigMaps t)+  => (HasNoNestedBigMaps t => a)   -> a-checkBigMapConstraint a =-  case bigMapConstrained (sing @t) of-    Just Dict -> a-    Nothing -> error "impossible"+forbiddenNestedBigMaps = withDict $ forbiddenNestedBigMapsEvi @t +-- | Reify 'HasNoContract' contraint from 'ForbidContract'.+forbiddenContractTypeEvi+  :: forall t. (SingI t, ForbidContract t) :- HasNoContract t+forbiddenContractTypeEvi = Sub $+  case checkContractTypePresence (sing @t) of+    ContractAbsent -> Dict+    ContractPresent -> error "impossible"++-- | Reify 'HasNoContract' contraint from 'ForbidContract'.+forbiddenContractType+  :: forall t a.+     (SingI t, ForbidContract t)+  => (HasNoContract t => a)+  -> a+forbiddenContractType = withDict $ forbiddenContractTypeEvi @t+ -- | Whether the type contains 'TOperation', with proof. data OpPresence (t :: T)   = ContainsOp t ~ 'True => OpPresent   | ContainsOp t ~ 'False => OpAbsent +data ContractPresence (t :: T)+  = ContainsContract t ~ 'True => ContractPresent+  | ContainsContract t ~ 'False => ContractAbsent+ data BigMapPresence (t :: T)   = ContainsBigMap t ~ 'True => BigMapPresent   | ContainsBigMap t ~ 'False => BigMapAbsent +data NestedBigMapsPresence (t :: T)+  = ContainsNestedBigMaps t ~ 'True => NestedBigMapsPresent+  | ContainsNestedBigMaps t ~ 'False => NestedBigMapsAbsent+ -- @rvem: IMO, generalization of OpPresence and BigMapPresence to -- TPresence is not worth it, due to the fact that -- it will require more boilerplate in checkTPresence implementation@@ -177,6 +338,7 @@   STc _ -> OpAbsent   STKey -> OpAbsent   STSignature -> OpAbsent+  STChainId -> OpAbsent   STUnit -> OpAbsent   STOption t -> case checkOpPresence t of     OpPresent -> OpPresent@@ -205,6 +367,39 @@     OpPresent -> OpPresent     OpAbsent -> OpAbsent +-- | Check at runtime whether the given type contains 'TContract'.+checkContractTypePresence :: Sing (ty :: T) -> ContractPresence ty+checkContractTypePresence = \case+  STc _ -> ContractAbsent+  STKey -> ContractAbsent+  STSignature -> ContractAbsent+  STChainId -> ContractAbsent+  STUnit -> ContractAbsent+  STOption t -> case checkContractTypePresence t of+    ContractPresent -> ContractPresent+    ContractAbsent -> ContractAbsent+  STList t -> case checkContractTypePresence t of+    ContractPresent -> ContractPresent+    ContractAbsent -> ContractAbsent+  STSet _ -> ContractAbsent+  STOperation -> ContractAbsent+  STContract _ -> ContractPresent+  STPair a b -> case (checkContractTypePresence a, checkContractTypePresence b) of+    (ContractPresent, _) -> ContractPresent+    (_, ContractPresent) -> ContractPresent+    (ContractAbsent, ContractAbsent) -> ContractAbsent+  STOr a b -> case (checkContractTypePresence a, checkContractTypePresence b) of+    (ContractPresent, _) -> ContractPresent+    (_, ContractPresent) -> ContractPresent+    (ContractAbsent, ContractAbsent) -> ContractAbsent+  STLambda _ _ -> ContractAbsent+  STMap _ v -> case checkContractTypePresence v of+    ContractPresent -> ContractPresent+    ContractAbsent -> ContractAbsent+  STBigMap _ v -> case checkContractTypePresence v of+    ContractPresent -> ContractPresent+    ContractAbsent -> ContractAbsent+ -- | Check at runtime whether the given type contains 'TBigMap'. checkBigMapPresence :: Sing (ty :: T) -> BigMapPresence ty checkBigMapPresence = \case@@ -212,6 +407,7 @@   STc _ -> BigMapAbsent   STKey -> BigMapAbsent   STSignature -> BigMapAbsent+  STChainId -> BigMapAbsent   STUnit -> BigMapAbsent   STOption t -> case checkBigMapPresence t of     BigMapPresent -> BigMapPresent@@ -239,94 +435,146 @@   STBigMap _ _ ->     BigMapPresent +-- | Check at runtime whether the given type contains 'TBigMap'.+checkNestedBigMapsPresence :: Sing (ty :: T) -> NestedBigMapsPresence ty+checkNestedBigMapsPresence = \case+  -- More boilerplate to boilerplate god.+  STc _ -> NestedBigMapsAbsent+  STKey -> NestedBigMapsAbsent+  STSignature -> NestedBigMapsAbsent+  STChainId -> NestedBigMapsAbsent+  STUnit -> NestedBigMapsAbsent+  STOption t -> case checkNestedBigMapsPresence t of+    NestedBigMapsPresent -> NestedBigMapsPresent+    NestedBigMapsAbsent -> NestedBigMapsAbsent+  STList                   t -> case checkNestedBigMapsPresence t of+    NestedBigMapsPresent -> NestedBigMapsPresent+    NestedBigMapsAbsent -> NestedBigMapsAbsent+  STSet _ -> NestedBigMapsAbsent+  STOperation -> NestedBigMapsAbsent+  STContract t -> case checkNestedBigMapsPresence t of+    NestedBigMapsPresent -> NestedBigMapsPresent+    NestedBigMapsAbsent -> NestedBigMapsAbsent+  STPair a b -> case (checkNestedBigMapsPresence a, checkNestedBigMapsPresence b) of+    (NestedBigMapsPresent, _) -> NestedBigMapsPresent+    (_, NestedBigMapsPresent) -> NestedBigMapsPresent+    (NestedBigMapsAbsent, NestedBigMapsAbsent) -> NestedBigMapsAbsent+  STOr a b -> case (checkNestedBigMapsPresence a, checkNestedBigMapsPresence b) of+    (NestedBigMapsPresent, _) -> NestedBigMapsPresent+    (_, NestedBigMapsPresent) -> NestedBigMapsPresent+    (NestedBigMapsAbsent, NestedBigMapsAbsent) -> NestedBigMapsAbsent+  STLambda _ _ -> NestedBigMapsAbsent+  STMap _ v -> case checkNestedBigMapsPresence v of+    NestedBigMapsPresent -> NestedBigMapsPresent+    NestedBigMapsAbsent -> NestedBigMapsAbsent+  STBigMap _ v -> case checkBigMapPresence v of+    BigMapPresent -> NestedBigMapsPresent+    BigMapAbsent -> NestedBigMapsAbsent+ -- | Check at runtime that the given type does not contain 'TOperation'. opAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoOp t) opAbsense s = case checkOpPresence s of   OpPresent -> Nothing   OpAbsent -> Just Dict +-- | Check at runtime that the given type does not contain 'TContract'.+contractTypeAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoContract t)+contractTypeAbsense s = case checkContractTypePresence s of+  ContractPresent -> Nothing+  ContractAbsent -> Just Dict+ -- | Check at runtime that the given type does not containt 'TBigMap' bigMapAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoBigMap t) bigMapAbsense s = case checkBigMapPresence s of   BigMapPresent -> Nothing   BigMapAbsent -> Just Dict --- | Check at runtime that the given type optionally has bigmap---   only on the left of its toplevel pair, which is actuall constraint for---   bigmap appearance in the storage-bigMapConstrained :: Sing (t :: T) -> Maybe (Dict $ BigMapConstraint t)-bigMapConstrained = \case-  -- Yet another bunch of boilerplate-  -- We have to make pattern matching on first argument of STPair-  -- to prove, that BigMap appears only on its leftmost position,-  -- and also make pattern matching on all Sing constructors-  -- to prove that TPair appears only in STPair-  STPair (STBigMap _ v) b ->-    case (bigMapAbsense v, bigMapAbsense b) of-      (Just Dict, Just Dict) -> Just Dict-      _ -> Nothing-  STPair (STc _) b -> case bigMapAbsense b of-    Just Dict -> Just Dict-    Nothing -> Nothing-  STPair STKey b -> case bigMapAbsense b of-    Just Dict -> Just Dict-    Nothing -> Nothing-  STPair STUnit b -> case bigMapAbsense b of-    Just Dict -> Just Dict-    Nothing -> Nothing-  STPair STSignature b -> case bigMapAbsense b of-    Just Dict -> Just Dict-    Nothing -> Nothing-  STPair (STOption a) b -> case (bigMapAbsense a, bigMapAbsense b) of-    (Just Dict, Just Dict) -> Just Dict-    _ -> Nothing-  STPair (STList a) b -> case (bigMapAbsense a, bigMapAbsense b) of-    (Just Dict, Just Dict) -> Just Dict-    _ -> Nothing-  STPair (STSet _) b -> case bigMapAbsense b of-    Just Dict -> Just Dict-    Nothing -> Nothing-  STPair STOperation b ->  case bigMapAbsense b of-    Just Dict -> Just Dict-    Nothing -> Nothing-  STPair (STContract a) b -> case (bigMapAbsense a, bigMapAbsense b) of-    (Just Dict, Just Dict) -> Just Dict-    _ -> Nothing-  STPair (STPair a b) c ->-    case (bigMapAbsense a, bigMapAbsense b, bigMapAbsense c) of-      (Just Dict, Just Dict, Just Dict) -> Just Dict-      _ -> Nothing-  STPair (STOr a b) c ->-    case (bigMapAbsense a, bigMapAbsense b, bigMapAbsense c) of-      (Just Dict, Just Dict, Just Dict) -> Just Dict-      _ -> Nothing-  STPair (STLambda _ _) c ->-    case bigMapAbsense c of-      Just Dict -> Just Dict-      Nothing -> Nothing-  STPair (STMap _ v) b -> case (bigMapAbsense v, bigMapAbsense b) of-    (Just Dict, Just Dict) -> Just Dict-    _ -> Nothing-  STc _ -> Just Dict-  STKey -> Just Dict-  STSignature -> Just Dict-  STUnit -> Just Dict-  STOption t -> case bigMapAbsense t of-    Just Dict -> Just Dict-    Nothing -> Nothing-  STList t -> case bigMapAbsense t of-    Just Dict -> Just Dict-    Nothing -> Nothing-  STSet _ -> Just Dict-  STOperation -> Just Dict-  STContract t -> case bigMapAbsense t of-    Just Dict -> Just Dict-    Nothing -> Nothing-  STOr a b -> case (bigMapAbsense a, bigMapAbsense b) of-    (Just Dict, Just Dict) -> Just Dict-    _ -> Nothing-  STLambda _ _ -> Just Dict-  STMap _ v -> case bigMapAbsense v of-    Just Dict -> Just Dict-    Nothing -> Nothing-  STBigMap _ _ -> Nothing+-- | Check at runtime that the given type does not contain nested 'TBigMap'+nestedBigMapsAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoNestedBigMaps t)+nestedBigMapsAbsense s = case checkNestedBigMapsPresence s of+  NestedBigMapsPresent -> Nothing+  NestedBigMapsAbsent -> Just Dict++----------------------------------------------------------------------------+-- Scopes+----------------------------------------------------------------------------++-- | Alias for constraints which Michelson applies to parameter.+type ParameterScope t =+  (Typeable t, SingI t, HasNoOp t, HasNoNestedBigMaps t)++-- | Alias for constraints which Michelson applies to contract storage.+type StorageScope t =+  (Typeable t, SingI t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t)++-- | Alias for constraints which Michelson applies to pushed constants.+type ConstantScope t =+  (SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t)++-- | Alias for constraints which Michelson applies to packed values.+type PackedValScope t =+  (SingI t, HasNoOp t, HasNoBigMap t)++-- | Alias for constraints which Michelson applies to unpacked values.+--+-- It is different from 'PackedValScope', e.g. @contract@ type cannot appear+-- in a value we unpack to.+type UnpackedValScope t =+  (PackedValScope t, ConstantScope t)++-- | Alias for constraints which are required for printing.+type PrintedValScope t = (SingI t, HasNoOp t)++-- Versions for eDSL+----------------------------------------------------------------------------++{- These constraints are supposed to be used only in eDSL code and eDSL should+define its own wrapers over it.+-}++type ProperParameterBetterErrors t =+  (Typeable t, SingI t, ForbidOp t, ForbidNestedBigMaps t)++type ProperStorageBetterErrors t =+  (Typeable t, SingI t, ForbidOp t, ForbidNestedBigMaps t, ForbidContract t)++type ProperConstantBetterErrors t =+  (SingI t, ForbidOp t, ForbidBigMap t, ForbidContract t)++type ProperPackedValBetterErrors t =+  (SingI t, ForbidOp t, ForbidBigMap t)++type ProperUnpackedValBetterErrors t =+  (ProperPackedValBetterErrors t, ProperConstantBetterErrors t)++type ProperPrintedValBetterErrors t =+  (SingI t, ForbidOp t)++properParameterEvi :: forall t. ProperParameterBetterErrors t :- ParameterScope t+properParameterEvi = Sub $+  Dict \\ forbiddenOpEvi @t \\ forbiddenNestedBigMapsEvi @t++properStorageEvi :: forall t. ProperStorageBetterErrors t :- StorageScope t+properStorageEvi = Sub $+  Dict \\ forbiddenOpEvi @t+       \\ forbiddenContractTypeEvi @t+       \\ forbiddenNestedBigMapsEvi @t+       \\ forbiddenContractTypeEvi @t++properConstantEvi :: forall t. ProperConstantBetterErrors t :- ConstantScope t+properConstantEvi = Sub $+  Dict \\ forbiddenOpEvi @t+       \\ forbiddenBigMapEvi @t+       \\ forbiddenContractTypeEvi @t++properPackedValEvi :: forall t. ProperPackedValBetterErrors t :- PackedValScope t+properPackedValEvi = Sub $+  Dict \\ forbiddenOpEvi @t+       \\ forbiddenBigMapEvi @t++properUnpackedValEvi :: forall t. ProperUnpackedValBetterErrors t :- UnpackedValScope t+properUnpackedValEvi = properPackedValEvi @t C.*** properConstantEvi @t++properPrintedValEvi :: forall t. ProperPrintedValBetterErrors t :- PrintedValScope t+properPrintedValEvi = Sub $+  Dict \\ forbiddenOpEvi @t
src/Michelson/Typed/Sing.hs view
@@ -41,6 +41,7 @@   STKey :: Sing  'TKey   STUnit :: Sing  'TUnit   STSignature :: Sing  'TSignature+  STChainId :: Sing  'TChainId   STOption :: (SingI a, Typeable a) => Sing a -> Sing ( 'TOption a)   STList :: (SingI a, Typeable a) => Sing a -> Sing ( 'TList a )   STSet :: (SingI a, Typeable a) => Sing a -> Sing ( 'TSet a )@@ -152,6 +153,7 @@ fromSingT STKey = TKey fromSingT STUnit = TUnit fromSingT STSignature = TSignature+fromSingT STChainId = TChainId fromSingT (STOption t) = TOption (fromSingT t) fromSingT (STList t) = TList (fromSingT t) fromSingT (STSet t) = TSet (fromSingCT t)@@ -169,6 +171,7 @@ toSingT TKey = SomeSingT STKey toSingT TUnit = SomeSingT STUnit toSingT TSignature = SomeSingT STSignature+toSingT TChainId = SomeSingT STChainId toSingT (TOption t) = withSomeSingT t $ \tSing -> SomeSingT $ STOption tSing toSingT (TList t) = withSomeSingT t $ \tSing -> SomeSingT $ STList tSing toSingT (TSet ct) = withSomeSingCT ct $ \ctSing -> SomeSingT $ STSet ctSing@@ -209,6 +212,8 @@   sing = STUnit instance SingI  'TSignature where   sing = STSignature+instance SingI  'TChainId where+  sing = STChainId instance (SingI a, Typeable a) => SingI ( 'TOption (a :: T)) where   sing = STOption sing instance (SingI a, Typeable a) => SingI ( 'TList (a :: T)) where
src/Michelson/Typed/T.hs view
@@ -5,9 +5,14 @@ module Michelson.Typed.T   ( CT (..)   , T (..)+  , toUType+  , buildStack   ) where -import Michelson.Untyped.Type (CT(..))+import Fmt (Buildable(..), Builder, listF)+import qualified Michelson.Untyped.Annotation as Un+import Michelson.Untyped.Type (CT)+import qualified Michelson.Untyped.Type as Un  -- | Michelson language type with annotations stripped off. data T =@@ -15,6 +20,7 @@   | TKey   | TUnit   | TSignature+  | TChainId   | TOption T   | TList T   | TSet CT@@ -26,3 +32,36 @@   | TMap CT T   | TBigMap CT T   deriving (Eq, Show)++-- | Converts from 'T' to 'Michelson.Type.Type'.+toUType :: T -> Un.Type+toUType t = Un.Type (convert t) Un.noAnn+  where+    convert :: T -> Un.T+    convert (Tc a) = Un.Tc a+    convert (TKey) = Un.TKey+    convert (TUnit) = Un.TUnit+    convert (TSignature) = Un.TSignature+    convert (TChainId) = Un.TChainId+    convert (TOption a) = Un.TOption (toUType a)+    convert (TList a) = Un.TList (toUType a)+    convert (TSet a) = Un.TSet $ Un.Comparable a Un.noAnn+    convert (TOperation) = Un.TOperation+    convert (TContract a) = Un.TContract (toUType a)+    convert (TPair a b) =+      Un.TPair Un.noAnn Un.noAnn (toUType a) (toUType b)+    convert (TOr a b) =+      Un.TOr Un.noAnn Un.noAnn (toUType a) (toUType b)+    convert (TLambda a b) =+      Un.TLambda (toUType a) (toUType b)+    convert (TMap a b) =+      Un.TMap (Un.Comparable a Un.noAnn) (toUType b)+    convert (TBigMap a b) =+      Un.TBigMap (Un.Comparable a Un.noAnn) (toUType b)++instance Buildable T where+  build = build . toUType++-- | Format type stack in a pretty way.+buildStack :: [T] -> Builder+buildStack = listF
+ src/Michelson/Typed/Util.hs view
@@ -0,0 +1,415 @@+-- | General-purpose utility functions for typed types.++module Michelson.Typed.Util+  ( DfsSettings (..)+  , CtorEffectsApp (..)+  , dfsInstr+  , dfsFoldInstr+  , dfsModifyInstr++  -- * Changing instruction tree structure+  , linearizeLeft++  -- * Value analysis+  , isStringValue+  , isBytesValue+  , allAtomicValues+  ) where++import Prelude hiding (Ordering(..))++import Data.Default (Default(..))+import qualified Text.Show++import Michelson.Text (MText)+import Michelson.Typed.Aliases+import Michelson.Typed.Instr+import Michelson.Typed.Value++-- | Options for 'dfsInstr'.+data DfsSettings x = DfsSettings+  { dsGoToValues :: Bool+    -- ^ Whether 'dfsInstr' function should go into values which contain other+    -- instructions: lambdas and constant contracts+    -- (which can be passed to @CREATE_CONTRACT@).+  , dsCtorEffectsApp :: CtorEffectsApp x+    -- ^ How do we handle intermediate nodes in instruction tree.+  } deriving (Show)++-- | Describes how intermediate nodes in instruction tree are accounted.+data CtorEffectsApp x = CtorEffectsApp+  { ceaName :: Text+    -- ^ Name of this way.+  , ceaApplyEffects+      :: forall i o. Semigroup x => x -> x -> Instr i o -> (Instr i o, x)+    -- ^ This function accepts:+    -- 1. Effects gathered after applying @step@ to node's children, but+    -- before applying it to the node itself.+    -- 2. Effects gathered after applying @step@ to the given intermediate node.+    -- 3. Instruction resulting after all modifications produced by @step@.+  }++instance Show (CtorEffectsApp x) where+  show CtorEffectsApp{..} = show ceaName++-- | Gather effects first for children nodes, then for their parents.+ceaBottomToTop :: CtorEffectsApp x+ceaBottomToTop = CtorEffectsApp+  { ceaName = "Apply after"+  , ceaApplyEffects =+      \effBefore effAfter instr -> (instr, effBefore <> effAfter)+  }++instance Default (DfsSettings x) where+  def = DfsSettings+    { dsGoToValues = False+    , dsCtorEffectsApp = ceaBottomToTop+    }++-- | Traverse a typed instruction in depth-first order.+-- '<>' is used to concatenate intermediate results.+-- Each instructions can be changed using the supplied @step@ function.+-- It does not consider extra instructions (not present in Michelson).+dfsInstr ::+     forall x inp out. Semigroup x+  => DfsSettings x+  -> (forall i o. Instr i o -> (Instr i o, x))+  -> Instr inp out+  -> (Instr inp out, x)+dfsInstr settings@DfsSettings{..} step i =+  case i of+    Seq i1 i2 -> recursion2 Seq i1 i2+    InstrWithNotes notes i1 -> recursion1 (InstrWithNotes notes) i1+    FrameInstr p i1 -> recursion1 (FrameInstr p) i1+    Nested i1 -> recursion1 Nested i1+    DocGroup dg i1 -> recursion1 (DocGroup dg) i1+    IF_NONE i1 i2 -> recursion2 IF_NONE i1 i2+    IF_LEFT i1 i2 -> recursion2 IF_LEFT i1 i2+    IF_CONS i1 i2 -> recursion2 IF_CONS i1 i2+    IF i1 i2 -> recursion2 IF i1 i2+    MAP i1 -> recursion1 MAP i1+    ITER i1 -> recursion1 ITER i1+    LOOP i1 -> recursion1 LOOP i1+    LOOP_LEFT i1 -> recursion1 LOOP_LEFT i1+    DIP i1 -> recursion1 DIP i1+    DIPN s i1 -> recursion1 (DIPN s) i1+    PUSH v -> case v of+      VLam i1 | dsGoToValues ->+        -- Using 'analyzeInstrFailure' here (and in case below) is cheap+        -- (O(n) in total) because we never make it run over the same code twice+        recursion1 (PUSH . VLam . analyzeInstrFailure) (rfAnyInstr i1)+      _ -> step i+    LAMBDA (VLam i1)+      | dsGoToValues ->+          recursion1 (LAMBDA . VLam . analyzeInstrFailure) (rfAnyInstr i1)+      | otherwise -> step i+    CREATE_CONTRACT contract+      | dsGoToValues ->+        let updateContractCode code = CREATE_CONTRACT $ contract{ fcCode = code }+        in recursion1 updateContractCode $ fcCode contract+      | otherwise -> step i++    Nop{} -> step i+    Ext{} -> step i+    AnnCAR{} -> step i+    AnnCDR{} -> step i+    DROP{} -> step i+    DROPN{} -> step i+    DUP{} -> step i+    SWAP{} -> step i+    DIG{} -> step i+    DUG{} -> step i+    SOME{} -> step i+    NONE{} -> step i+    UNIT{} -> step i+    PAIR{} -> step i+    LEFT{} -> step i+    RIGHT{} -> step i+    NIL{} -> step i+    CONS{} -> step i+    SIZE{} -> step i+    EMPTY_SET{} -> step i+    EMPTY_MAP{} -> step i+    EMPTY_BIG_MAP{} -> step i+    MEM{} -> step i+    GET{} -> step i+    UPDATE{} -> step i+    EXEC{} -> step i+    APPLY{} -> step i+    FAILWITH{} -> step i+    CAST{} -> step i+    RENAME{} -> step i+    PACK{} -> step i+    UNPACK{} -> step i+    CONCAT{} -> step i+    CONCAT'{} -> step i+    SLICE{} -> step i+    ISNAT{} -> step i+    ADD{} -> step i+    SUB{} -> step i+    MUL{} -> step i+    EDIV{} -> step i+    ABS{} -> step i+    NEG{} -> step i+    LSL{} -> step i+    LSR{} -> step i+    OR{} -> step i+    AND{} -> step i+    XOR{} -> step i+    NOT{} -> step i+    COMPARE{} -> step i+    EQ{} -> step i+    NEQ{} -> step i+    LT{} -> step i+    GT{} -> step i+    LE{} -> step i+    GE{} -> step i+    INT{} -> step i+    SELF{} -> step i+    CONTRACT{} -> step i+    TRANSFER_TOKENS{} -> step i+    SET_DELEGATE{} -> step i+    IMPLICIT_ACCOUNT{} -> step i+    NOW{} -> step i+    AMOUNT{} -> step i+    BALANCE{} -> step i+    CHECK_SIGNATURE{} -> step i+    SHA256{} -> step i+    SHA512{} -> step i+    BLAKE2B{} -> step i+    HASH_KEY{} -> step i+    STEPS_TO_QUOTA{} -> step i+    SOURCE{} -> step i+    SENDER{} -> step i+    ADDRESS{} -> step i+    CHAIN_ID{} -> step i+  where+    recursion1 ::+      forall a b c d. (Instr a b -> Instr c d) -> Instr a b -> (Instr c d, x)+    recursion1 constructor i0 =+      let+        (innerI, innerX) = dfsInstr settings step i0+        (outerI, outerX) = step $ constructor innerI+      in ceaApplyEffects dsCtorEffectsApp innerX outerX outerI++    recursion2 ::+      forall i o i1 o1 i2 o2.+      (Instr i1 o1 -> Instr i2 o2 -> Instr i o) ->+      Instr i1 o1 -> Instr i2 o2 -> (Instr i o, x)+    recursion2 constructor i1 i2 =+      let+        (i1', x1) = dfsInstr settings step i1+        (i2', x2) = dfsInstr settings step i2+        (i', x) = step $ constructor i1' i2'+      in ceaApplyEffects dsCtorEffectsApp (x1 <> x2) x i'++-- | Specialization of 'dfsInstr' for case when changing the instruction is+-- not required.+dfsFoldInstr+  :: forall x inp out.+      (Semigroup x)+  => DfsSettings x+  -> (forall i o. Instr i o -> x)+  -> Instr inp out+  -> x+dfsFoldInstr settings step instr =+  snd $ dfsInstr settings (\i -> (i, step i)) instr++-- | Specialization of 'dfsInstr' which only modifies given instruction.+dfsModifyInstr+  :: DfsSettings ()+  -> (forall i o. Instr i o -> Instr i o)+  -> Instr inp out+  -> Instr inp out+dfsModifyInstr settings step instr =+  fst $ dfsInstr settings (\i -> (step i, ())) instr++-- | Check whether instruction fails at each execution path or have at least one+-- non-failing path.+--+-- This function assumes that given instruction contains no dead code+-- (contract with dead code cannot be valid Michelson contract) and may behave+-- in unexpected way if such is present. Term "dead code" includes instructions+-- which render into empty Michelson, like Morley extensions.+-- On the other hand, this function does not traverse the whole instruction tree;+-- performs fastest on left-growing combs.+--+-- Often we already have information about instruction failure, use this+-- function only in cases when this info is actually unavailable or hard+-- to use.+analyzeInstrFailure :: HasCallStack => Instr i o -> RemFail Instr i o+analyzeInstrFailure = go+  where+  go :: Instr i o -> RemFail Instr i o+  go = \case+    InstrWithNotes pn i -> case go i of+      RfNormal i0 ->+        RfNormal (InstrWithNotes pn i0)+      RfAlwaysFails i0 ->+        error $ "InstrWithNotes wraps always-failing instruction: " <> show i0+    FrameInstr s i -> case go i of+      RfNormal i0 ->+        RfNormal (FrameInstr s i0)+      RfAlwaysFails i0 ->+        error $ "FrameInstr wraps always-failing instruction: " <> show i0+    Seq a b -> Seq a `rfMapAnyInstr` go b+    Nop -> RfNormal Nop+    Ext e -> RfNormal (Ext e)+    Nested i -> Nested `rfMapAnyInstr` go i+    DocGroup g i -> DocGroup g `rfMapAnyInstr` go i++    IF_NONE l r -> rfMerge IF_NONE (go l) (go r)+    IF_LEFT l r -> rfMerge IF_LEFT (go l) (go r)+    IF_CONS l r -> rfMerge IF_CONS (go l) (go r)+    IF l r -> rfMerge IF (go l) (go r)++    i@MAP{} -> RfNormal i+    i@ITER{} -> RfNormal i+    i@LOOP{} -> RfNormal i+    i@LOOP_LEFT{} -> RfNormal i+    i@LAMBDA{} -> RfNormal i+    i@DIP{} -> RfNormal i+    i@DIPN{} -> RfNormal i++    i@AnnCAR{} -> RfNormal i+    i@AnnCDR{} -> RfNormal i+    i@DROP{} -> RfNormal i+    i@DROPN{} -> RfNormal i+    i@DUP{} -> RfNormal i+    i@SWAP{} -> RfNormal i+    i@DIG{} -> RfNormal i+    i@DUG{} -> RfNormal i+    i@PUSH{} -> RfNormal i+    i@SOME{} -> RfNormal i+    i@NONE{} -> RfNormal i+    i@UNIT{} -> RfNormal i+    i@PAIR{} -> RfNormal i+    i@LEFT{} -> RfNormal i+    i@RIGHT{} -> RfNormal i+    i@NIL{} -> RfNormal i+    i@CONS{} -> RfNormal i+    i@SIZE{} -> RfNormal i+    i@EMPTY_SET{} -> RfNormal i+    i@EMPTY_MAP{} -> RfNormal i+    i@EMPTY_BIG_MAP{} -> RfNormal i+    i@MEM{} -> RfNormal i+    i@GET{} -> RfNormal i+    i@UPDATE{} -> RfNormal i+    i@EXEC{} -> RfNormal i+    i@APPLY{} -> RfNormal i+    FAILWITH -> RfAlwaysFails FAILWITH+    i@CAST -> RfNormal i+    i@RENAME -> RfNormal i+    i@PACK -> RfNormal i+    i@UNPACK -> RfNormal i+    i@CONCAT -> RfNormal i+    i@CONCAT' -> RfNormal i+    i@SLICE -> RfNormal i+    i@ISNAT -> RfNormal i+    i@ADD -> RfNormal i+    i@SUB -> RfNormal i+    i@MUL -> RfNormal i+    i@EDIV -> RfNormal i+    i@ABS -> RfNormal i+    i@NEG -> RfNormal i+    i@LSL -> RfNormal i+    i@LSR -> RfNormal i+    i@OR -> RfNormal i+    i@AND -> RfNormal i+    i@XOR -> RfNormal i+    i@NOT -> RfNormal i+    i@COMPARE -> RfNormal i+    i@EQ -> RfNormal i+    i@NEQ -> RfNormal i+    i@LT -> RfNormal i+    i@GT -> RfNormal i+    i@LE -> RfNormal i+    i@GE -> RfNormal i+    i@INT -> RfNormal i+    i@SELF -> RfNormal i+    i@CONTRACT{} -> RfNormal i+    i@TRANSFER_TOKENS -> RfNormal i+    i@SET_DELEGATE -> RfNormal i+    i@CREATE_CONTRACT{} -> RfNormal i+    i@IMPLICIT_ACCOUNT -> RfNormal i+    i@NOW -> RfNormal i+    i@AMOUNT -> RfNormal i+    i@BALANCE -> RfNormal i+    i@CHECK_SIGNATURE -> RfNormal i+    i@SHA256 -> RfNormal i+    i@SHA512 -> RfNormal i+    i@BLAKE2B -> RfNormal i+    i@HASH_KEY -> RfNormal i+    i@STEPS_TO_QUOTA -> RfNormal i+    i@SOURCE -> RfNormal i+    i@SENDER -> RfNormal i+    i@ADDRESS -> RfNormal i+    i@CHAIN_ID -> RfNormal i++-- | There are many ways to represent a sequence of more than 2 instructions.+-- E. g. for `i1; i2; i3` it can be @Seq i1 $ Seq i2 i3@ or @Seq (Seq i1 i2) i3@.+-- This function enforces a particular structure. Specifically, it makes each+-- 'Seq' have a single instruction (i. e. not 'Seq') in its second argument.+-- This function also erases redundant 'Nop's.+linearizeLeft :: Instr inp out -> Instr inp out+linearizeLeft = linearizeLeftHelper False+  where+    -- In order to avoid quadratic performance we make a simple optimization.+    -- We track whether left argument of `Seq` is already linearized.+    -- If it is, we do not need to ever linearize it again.+    linearizeLeftHelper :: Bool -> Instr inp out -> Instr inp out+    linearizeLeftHelper isLeftInstrAlreadyLinear =+      \case+        Seq i1 (Seq i2 i3) ->+          linearizeLeftHelper True $+          Seq (linearizeLeftHelper isLeftInstrAlreadyLinear (Seq i1 i2)) i3+        -- `i2` is not a `Seq`, so we only need to linearize `i1`+        -- and connect it with `i2`.+        Seq i1 i2+          | isLeftInstrAlreadyLinear+          , Nop <- i2 -> i1+          | isLeftInstrAlreadyLinear -> Seq i1 i2+          | Nop <- i2 -> linearizeLeft i1+          | otherwise -> Seq (linearizeLeft i1) i2+        i -> i++----------------------------------------------------------------------------+-- Value analysis+----------------------------------------------------------------------------++-- | If value is a string, return the stored string.+isStringValue :: Value t -> Maybe MText+isStringValue =+  \case+    VC (CvString str) -> Just str+    _ -> Nothing++-- | If value is a bytestring, return the stored bytestring.+isBytesValue :: Value t -> Maybe ByteString+isBytesValue =+  \case+    VC (CvBytes bytes) -> Just bytes+    _ -> Nothing++-- | Takes a selector which checks whether an atomic value (i. e. that+-- can not contain another value) can be converted to something.+-- Recursively applies it to all atomic values in potentially+-- non-atomic value.  Collects extracted values in a list.+--+-- Perhaps one day we'll have `dfsValue`.+allAtomicValues ::+  forall t a. (forall t'. Value t' -> Maybe a) -> Value t -> [a]+allAtomicValues selector = go+  where+    go :: forall x. Value x -> [a]+    go = \case+      VList l -> foldMap go l+      VSet s -> foldMap (go . VC) s+      VPair (l, r) -> go l <> go r+      VOr e -> either go go e+      VMap m -> goMap m+      VBigMap m -> goMap m+      v -> maybeToList $ selector v++    goMap :: Map (CValue k) (Value v) -> [a]+    goMap m = foldMap (go . VC) (keys m) <> foldMap go (toList m)
src/Michelson/Typed/Value.hs view
@@ -1,29 +1,42 @@+{-# LANGUAGE QuantifiedConstraints #-}+ -- | Module, containing data types for Michelson value.  module Michelson.Typed.Value   ( Value' (..)+  , SomeValue' (..)+  , SomeConstrainedValue' (..)   , ContractInp1   , ContractInp   , ContractOut1   , ContractOut-  , CreateAccount (..)   , CreateContract (..)   , CValue (..)   , Operation' (..)   , SetDelegate (..)   , TransferTokens (..)+  , RemFail (..)+  , rfMerge+  , rfAnyInstr+  , rfMapAnyInstr+  , addressToVContract+  , buildVContract+  , compileEpLiftSequence   ) where +import Data.Default (def) import Data.Singletons (SingI)-import Fmt (Buildable(build), (+|), (|+))+import Fmt (Buildable(build), (+|), (|+), Builder)+import qualified Data.Kind as Kind -import Michelson.EqParam import Michelson.Typed.CValue (CValue(..))-import Michelson.Typed.Scope (HasNoOp)+import Michelson.Typed.EntryPoints+import Michelson.Typed.Scope (ParameterScope, StorageScope) import Michelson.Typed.T (T(..)) import Tezos.Address (Address)-import Tezos.Core (Mutez)+import Tezos.Core (ChainId, Mutez) import Tezos.Crypto (KeyHash, PublicKey, Signature)+import Util.Typeable  -- | Data type, representing operation, list of which is returned -- by Michelson contract (according to calling convention).@@ -32,13 +45,12 @@ -- after the contract execution. data Operation' instr where   OpTransferTokens-    :: (Typeable p, SingI p, HasNoOp p)+    :: (ParameterScope 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 instr, Typeable cp, Typeable st, HasNoOp cp, HasNoOp st)+    :: ( Show (instr (ContractInp cp st) (ContractOut st))+       , Typeable instr, ParameterScope cp, StorageScope st)     => CreateContract instr cp st     -> Operation' instr @@ -47,7 +59,6 @@     \case       OpTransferTokens tt -> build tt       OpSetDelegate sd -> build sd-      OpCreateAccount ca -> build ca       OpCreateContract cc -> build cc  deriving instance Show (Operation' instr)@@ -57,22 +68,18 @@     (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 :: !(Value' instr p)+  { ttTransferArgument :: !(Value' instr p)   , ttAmount :: !Mutez   , ttContract :: !(Value' instr ('TContract p))   } deriving (Show, Eq)  instance Buildable (TransferTokens instr p) where   build TransferTokens {..} =-    "Transfer " +| ttAmount |+ " tokens to " +| destAddr |+ ""-    where-      destAddr = case ttContract of VContract addr -> addr+    "Transfer " +| ttAmount |+ " tokens to " +| buildVContract ttContract |+ ""  data SetDelegate = SetDelegate   { sdMbKeyHash :: !(Maybe KeyHash)@@ -82,29 +89,13 @@   build (SetDelegate mbDelegate) =     "Set delegate to " <> maybe "<nobody>" build mbDelegate -data CreateAccount = CreateAccount-  { caManager :: !KeyHash-  , caDelegate :: !(Maybe KeyHash)-  , caSpendable :: !Bool-  , caBalance :: !Mutez-  } deriving (Show, Eq)--instance Buildable CreateAccount where-  build CreateAccount {..} =-    "Create a new account with manager " +| caManager |+-    " and delegate " +| maybe "<nobody>" build caDelegate |+-    ", spendable: " +| caSpendable |+-    " and balance = " +| caBalance |+ ""- data CreateContract instr cp st   = ( Show (instr (ContractInp cp st) (ContractOut st))     , Eq (instr (ContractInp cp st) (ContractOut st))     )   => CreateContract-  { ccManager :: !KeyHash+  { ccOriginator :: !Address   , ccDelegate :: !(Maybe KeyHash)-  , ccSpendable :: !Bool-  , ccDelegatable :: !Bool   , ccBalance :: !Mutez   , ccStorageVal :: !(Value' instr st)   , ccContractCode :: !(instr (ContractInp cp st) (ContractOut st))@@ -112,10 +103,8 @@  instance Buildable (CreateContract instr cp st) where   build CreateContract {..} =-    "Create a new contract with manager " +| ccManager |+-    " and delegate " +| maybe "<nobody>" build ccDelegate |+-    ", spendable: " +| ccSpendable |+-    ", delegatable: " +| ccDelegatable |++    "Create a new contract with" <>+    " delegate " +| maybe "<nobody>" build ccDelegate |+     " and balance = " +| ccBalance |+ ""  deriving instance Show (CreateContract instr cp st)@@ -127,6 +116,46 @@ type ContractOut1 st = 'TPair ('TList 'TOperation) st type ContractOut st = '[ ContractOut1 st ] +-- | Wrapper over instruction which remembers whether this instruction+-- always fails or not.+data RemFail (instr :: k -> k -> Kind.Type) (i :: k) (o :: k) where+  RfNormal :: instr i o -> RemFail instr i o+  RfAlwaysFails :: (forall o'. instr i o') -> RemFail instr i o++deriving instance (forall o'. Show (instr i o')) => Show (RemFail instr i o)++-- | Ignoring distinction between constructors here, comparing only semantics.+instance Eq (instr i o) => Eq (RemFail instr i o) where+  RfNormal i1 == RfNormal i2 = i1 == i2+  RfAlwaysFails i1 == RfNormal i2 = i1 == i2+  RfNormal i1 == RfAlwaysFails i2 = i1 == i2+  RfAlwaysFails i1 == RfAlwaysFails i2 = i1 @o == i2++-- | Merge two execution branches.+rfMerge+  :: (forall o'. instr i1 o' -> instr i2 o' -> instr i3 o')+  -> RemFail instr i1 o -> RemFail instr i2 o -> RemFail instr i3 o+rfMerge merger instr1 instr2 = case (instr1, instr2) of+  (RfNormal i1, RfNormal i2) -> RfNormal (merger i1 i2)+  (RfAlwaysFails i1, RfNormal i2) -> RfNormal (merger i1 i2)+  (RfNormal i1, RfAlwaysFails i2) -> RfNormal (merger i1 i2)+  (RfAlwaysFails i1, RfAlwaysFails i2) -> RfAlwaysFails (merger i1 i2)++-- | Get code disregard whether it always fails or not.+rfAnyInstr :: RemFail instr i o -> instr i o+rfAnyInstr = \case+  RfNormal i -> i+  RfAlwaysFails i -> i++-- | Modify inner code.+rfMapAnyInstr+  :: (forall o'. instr i1 o' -> instr i2 o')+  -> RemFail instr i1 o+  -> RemFail instr i2 o+rfMapAnyInstr f = \case+  RfNormal i -> RfNormal $ f i+  RfAlwaysFails i -> RfAlwaysFails $ f i+ -- | Representation of Michelson value. -- -- Type parameter @instr@ stands for Michelson instruction@@ -137,24 +166,70 @@   VKey :: PublicKey -> Value' instr 'TKey   VUnit :: Value' instr 'TUnit   VSignature :: Signature -> Value' instr 'TSignature+  VChainId :: ChainId -> Value' instr 'TChainId   VOption :: forall t instr. Maybe (Value' instr t) -> Value' instr ('TOption t)   VList :: forall t instr. [Value' instr t] -> Value' instr ('TList t)   VSet :: forall t instr. Set (CValue t) -> Value' instr ('TSet t)   VOp :: Operation' instr -> Value' instr 'TOperation-  VContract :: forall p instr. Address -> Value' instr ('TContract p)+  VContract :: forall arg instr. Address -> SomeEntryPointCallT arg -> Value' instr ('TContract arg)   VPair :: forall l r instr. (Value' instr l, Value' instr r) -> Value' instr ('TPair l r)   VOr :: forall l r instr. Either (Value' instr l) (Value' instr r) -> Value' instr ('TOr l r)   VLam     :: forall inp out instr.-       ( Show (instr '[inp] '[out])-       , Eq (instr '[inp] '[out])+       ( forall i o.+          ( Show (instr i o)+          , Eq (instr i o)+          )        )-    => instr (inp ': '[]) (out ': '[]) -> Value' instr ('TLambda inp out)+    => RemFail instr (inp ': '[]) (out ': '[]) -> Value' instr ('TLambda inp out)   VMap :: forall k v instr. Map (CValue k) (Value' instr v) -> Value' instr ('TMap k v)   VBigMap :: forall k v instr. Map (CValue k) (Value' instr v) -> Value' instr ('TBigMap k v)  deriving instance Show (Value' instr t) deriving instance Eq (Value' instr t)++-- | Make value of 'contract' type which refers to the given address and+-- does not call any entrypoint.+addressToVContract+  :: forall t instr.+      ParameterScope t+  => Address -> Value' instr ('TContract t)+addressToVContract addr = VContract addr def++buildVContract :: Value' instr ('TContract arg) -> Builder+buildVContract = \case+  VContract addr epc -> "Contract " +| addr |+ " call " +| epc |+ ""++data SomeValue' instr where+  SomeValue :: (Typeable t, SingI t) => Value' instr t -> SomeValue' instr++deriving instance Show (SomeValue' instr)+instance Eq (SomeValue' instr) where+  SomeValue v1 == SomeValue v2 = v1 `eqParam1` v2++data SomeConstrainedValue' instr (c :: T -> Constraint) where+  SomeConstrainedValue+    :: forall (t :: T) (c :: T -> Constraint) instr+    . (c t)+    => Value' instr t+    -> SomeConstrainedValue' instr c++deriving instance Show (SomeConstrainedValue' instr c)++-- TODO+-- @gromak: perhaps we should implement `SomeValue'` in terms of+-- `SomeConstrainedValue'`, but it will require changing quite a lot of code,+-- so it is postponed.++-- | Turn 'EpLiftSequence' into actual function on 'Value's.+compileEpLiftSequence+  :: EpLiftSequence arg param+  -> Value' instr arg+  -> Value' instr param+compileEpLiftSequence = \case+  EplArgHere -> id+  EplWrapLeft els -> VOr . Left . compileEpLiftSequence els+  EplWrapRight els -> VOr . Right . compileEpLiftSequence els  -- TODO: actually we should handle big maps with something close -- to following:
src/Michelson/Untyped/Annotation.hs view
@@ -8,9 +8,11 @@   , TypeAnn   , FieldAnn   , VarAnn-  , RenderAnn (..)+  , SomeAnn   , noAnn   , ann+  , renderAnn+  , renderWEAnn   , unifyAnn   , ifAnnUnified   , disjoinVn@@ -34,67 +36,47 @@ instance Default (Annotation tag) where   def = Annotation "" -instance Show (Annotation FieldTag) where-  show (Annotation x) = "%" <> toString x--instance Show (Annotation VarTag) where-  show (Annotation x) = "@" <> toString x+class KnownAnnTag tag where+  annPrefix :: Text -instance Show (Annotation TypeTag) where-  show (Annotation x) = ":" <> toString x+instance KnownAnnTag tag => Show (Annotation tag) where+  show (Annotation x) = toString $ annPrefix @tag <> x  data TypeTag data FieldTag data VarTag+data SomeTag  type TypeAnn = Annotation TypeTag type FieldAnn = Annotation FieldTag type VarAnn = Annotation VarTag--instance RenderDoc TypeAnn where-  renderDoc = renderAnnotation ":"+type SomeAnn = Annotation SomeTag -instance RenderDoc FieldAnn where-  renderDoc = renderAnnotation "%"+instance KnownAnnTag FieldTag where+  annPrefix = "%"+instance KnownAnnTag VarTag where+  annPrefix = "@"+instance KnownAnnTag TypeTag where+  annPrefix = ":" -instance RenderDoc VarAnn where-  renderDoc = renderAnnotation "@"+instance KnownAnnTag tag => RenderDoc (Annotation tag) where+  renderDoc _ = renderAnn +renderAnn :: forall tag. KnownAnnTag tag => Annotation tag -> Doc+renderAnn a@(Annotation text)+  | a == noAnn = ""+  | otherwise = textStrict $ annPrefix @tag <> text --- | Typeclass for printing annotations, @renderAnn@--- prints empty prefix in case of @noAnn@.+-- | Prints empty prefix in case of @noAnn@. -- -- Such functionality is required in case when instruction -- has two annotations of the same type, former is empty -- and the latter is not. So that `PAIR noAnn noAnn noAnn %kek` -- is printed as `PAIR % %kek`-class RenderAnn t where-  renderAnn :: t -> Doc--instance RenderAnn TypeAnn where-  renderAnn = renderWithEmptyAnnotation ":"--instance RenderAnn FieldAnn where-  renderAnn = renderWithEmptyAnnotation "%"--instance RenderAnn VarAnn where-  renderAnn = renderWithEmptyAnnotation "@"--renderAnnotation :: Doc -> Annotation tag -> Doc-renderAnnotation prefix a@(Annotation text)-  | a == noAnn = ""-  | otherwise = prefix <> (textStrict text)--renderWithEmptyAnnotation :: Doc -> Annotation tag -> Doc-renderWithEmptyAnnotation prefix (Annotation text) = prefix <> (textStrict text)--instance Buildable TypeAnn where-  build = buildRenderDoc--instance Buildable FieldAnn where-  build = buildRenderDoc+renderWEAnn :: forall tag. KnownAnnTag tag => Annotation tag -> Doc+renderWEAnn (Annotation text) = textStrict $ annPrefix @tag <> text -instance Buildable VarAnn where+instance KnownAnnTag tag => Buildable (Annotation tag) where   build = buildRenderDoc  noAnn :: Annotation a
src/Michelson/Untyped/Contract.hs view
@@ -13,7 +13,8 @@ import Formatting.Buildable (Buildable(build)) import Text.PrettyPrint.Leijen.Text (nest, semi, (<$$>), (<+>)) -import Michelson.Printer.Util (RenderDoc(..), buildRenderDoc, renderOpsList)+import Michelson.Printer.Util+  (Prettier(..), RenderDoc(..), assertParensNotNeeded, buildRenderDoc, needsParens, renderOpsList) import Michelson.Untyped.Type (Type)  type Parameter = Type@@ -25,9 +26,9 @@   } deriving stock (Eq, Show, Functor, Data, Generic)  instance (RenderDoc op) => RenderDoc (Contract' op) where-  renderDoc (Contract parameter storage code) =-    "parameter" <+> renderDoc parameter  <> semi <$$>-    "storage"   <+> renderDoc storage    <> semi <$$>+  renderDoc pn (Contract parameter storage code) = assertParensNotNeeded pn $+    "parameter" <+> renderDoc needsParens (Prettier parameter)  <> semi <$$>+    "storage"   <+> renderDoc needsParens (Prettier storage)    <> semi <$$>     "code"      <+> nest (length ("code {" :: Text)) (renderOpsList False code <> semi)  instance RenderDoc op => Buildable (Contract' op) where
src/Michelson/Untyped/Ext.hs view
@@ -41,9 +41,9 @@   deriving (Eq, Show, Data, Generic, Functor)  instance RenderDoc op => RenderDoc (ExtInstrAbstract op) where-  renderDoc =+  renderDoc _ =     \case-      FN _ _ ops -> renderOpsList True ops+      FN _ _ ops -> renderOpsList False ops       _ -> mempty   isRenderable =     \case
src/Michelson/Untyped/Instr.hs view
@@ -4,12 +4,8 @@  module Michelson.Untyped.Instr   ( InstrAbstract (..)-  , Op (..)-  , Instr   , ExpandedOp (..)   , ExpandedInstr-  , InstrExtU-  , ExpandedInstrExtU   , flattenExpandedOp    -- * Contract's address@@ -17,18 +13,20 @@   , mkContractAddress   ) where +import Prelude hiding (EQ, GT, LT)+ import qualified Data.Aeson as Aeson import qualified Data.ByteString.Lazy as BSL import Data.Data (Data(..)) import Fmt (Buildable(build), (+|), (|+)) import Generics.SYB (everywhere, mkT)-import Prelude hiding (EQ, GT, LT)-import Text.PrettyPrint.Leijen.Text (braces, nest, (<$$>), (<+>))+import Text.PrettyPrint.Leijen.Text+  (Doc, align, braces, enclose, indent, line, nest, space, text, (<$$>), (<+>))  import Michelson.ErrorPos (InstrCallStack)-import Michelson.Printer.Util (RenderDoc(..), buildRenderDoc, renderOpsList, spaces)-import Michelson.Untyped.Annotation-  (FieldAnn, TypeAnn, VarAnn, RenderAnn(..))+import Michelson.Printer.Util+  (RenderDoc(..), buildRenderDoc, doesntNeedParens, needsParens, renderOpsList, spaces)+import Michelson.Untyped.Annotation (Annotation, FieldAnn, TypeAnn, VarAnn, noAnn, renderWEAnn) import Michelson.Untyped.Contract (Contract'(..)) import Michelson.Untyped.Ext (ExtInstrAbstract) import Michelson.Untyped.Type (Comparable, Type)@@ -38,19 +36,9 @@ import Tezos.Crypto (KeyHash)  ---------------------------------------- Flattened types after macroexpander---------------------------------------type InstrExtU = ExtInstrAbstract Op-type Instr = InstrAbstract Op-newtype Op = Op {unOp :: Instr}-  deriving stock (Show, Eq, Generic)-  deriving newtype (RenderDoc, Buildable)--------------------------------------- -- Types after macroexpander ------------------------------------- -type ExpandedInstrExtU = ExtInstrAbstract ExpandedOp type ExpandedInstr = InstrAbstract ExpandedOp  data ExpandedOp@@ -60,9 +48,9 @@   deriving stock (Show, Eq, Data, Generic)  instance RenderDoc ExpandedOp where-  renderDoc (WithSrcEx _ op) = renderDoc op-  renderDoc (PrimEx i) = renderDoc i-  renderDoc (SeqEx i)    = renderOpsList True i+  renderDoc pn (WithSrcEx _ op) = renderDoc pn op+  renderDoc pn (PrimEx i) = renderDoc pn i+  renderDoc _  (SeqEx i) = renderOpsList False i   isRenderable =     \case PrimEx i -> isRenderable i           WithSrcEx _ op -> isRenderable op@@ -78,9 +66,6 @@ -- not strictly equivalent, because they are serialized differently -- (grouping instructions into sequences affects the way they are -- PACK'ed).------ Note: it does not return a list of 'Instr' because this type is not--- used anywhere and should probably be removed. flattenExpandedOp :: ExpandedOp -> [ExpandedInstr] flattenExpandedOp =   \case@@ -108,12 +93,27 @@ -- Michelson instructions. data InstrAbstract op   = EXT               (ExtInstrAbstract op)+  | DROPN              Word+  -- ^ "DROP n" instruction.+  -- Note: reference implementation permits int16 here.+  -- Negative numbers are parsed successfully there, but rejected later.+  -- Morley is more permissive, so we use 'Word' here,+  -- i. e. permit more positive numbers. We do not permit negative numbers+  -- at type level.+  -- In practice, probably nobody will ever have numbers greater than ≈1000+  -- here, at least due to gas limits.+  -- Same reasoning applies to other instructions which have a numeric+  -- parameter representing number of elements on stack.   | DROP+  -- ^ 'DROP' is essentially as special case for 'DROPN', but we need+  -- both because they are packed differently.   | DUP               VarAnn   | SWAP+  | DIG               Word+  | DUG               Word   | PUSH              VarAnn Type (Value' op)-  | SOME              TypeAnn VarAnn FieldAnn-  | NONE              TypeAnn VarAnn FieldAnn Type+  | SOME              TypeAnn VarAnn+  | NONE              TypeAnn VarAnn Type   | UNIT              TypeAnn VarAnn   | IF_NONE           [op] [op]   | PAIR              TypeAnn VarAnn FieldAnn FieldAnn@@ -128,18 +128,21 @@   | SIZE              VarAnn   | EMPTY_SET         TypeAnn VarAnn Comparable   | EMPTY_MAP         TypeAnn VarAnn Comparable Type+  | EMPTY_BIG_MAP     TypeAnn VarAnn Comparable Type   | MAP               VarAnn [op]   | ITER              [op]   | MEM               VarAnn   | GET               VarAnn-  | UPDATE+  | UPDATE            VarAnn   | IF                [op] [op]   | LOOP              [op]   | LOOP_LEFT         [op]   | LAMBDA            VarAnn Type Type [op]   -- TODO check on alphanet whether we can pass TypeNote   | EXEC              VarAnn+  | APPLY             VarAnn   | DIP               [op]+  | DIPN              Word [op]   | FAILWITH   | CAST              VarAnn Type   | RENAME            VarAnn@@ -153,8 +156,7 @@   | MUL               VarAnn   | EDIV              VarAnn   | ABS               VarAnn-  -- TODO why no varnote for NEG-  | NEG+  | NEG               VarAnn   | LSL               VarAnn   | LSR               VarAnn   | OR                VarAnn@@ -169,11 +171,11 @@   | LE                VarAnn   | GE                VarAnn   | INT               VarAnn+    -- TODO [TM-280]: SELF now should contain field annotation as CONTRACT does   | SELF              VarAnn-  | CONTRACT          VarAnn Type+  | CONTRACT          VarAnn FieldAnn Type   | TRANSFER_TOKENS   VarAnn   | SET_DELEGATE      VarAnn-  | CREATE_ACCOUNT    VarAnn VarAnn   | CREATE_CONTRACT   VarAnn VarAnn (Contract' op)   | IMPLICIT_ACCOUNT  VarAnn   | NOW               VarAnn@@ -188,93 +190,111 @@   | SOURCE            VarAnn   | SENDER            VarAnn   | ADDRESS           VarAnn+  | CHAIN_ID          VarAnn   deriving (Eq, Show, Functor, Data, Generic)  instance (RenderDoc op) => RenderDoc (InstrAbstract op) where-  renderDoc = \case-    EXT extInstr          -> renderDoc extInstr-    DROP                  -> "DROP"-    DUP va                -> "DUP" <+> renderDoc va-    SWAP                  -> "SWAP"-    PUSH va t v           -> "PUSH" <+> renderDoc va <+> renderDoc t <+> renderDoc v-    SOME ta va fa         -> "SOME" <+> renderDoc ta <+> renderDoc va <+> renderDoc fa-    NONE ta va fa t       -> "NONE" <+> renderDoc ta <+> renderDoc va <+> renderDoc fa <+> renderDoc t-    UNIT ta va            -> "UNIT" <+> renderDoc ta <+> renderDoc va-    IF_NONE x y           -> "IF_NONE" <+> nest 9 (renderOps x) <$$> spaces 8 <> nest 9 (renderOps y)-    PAIR ta va fa1 fa2    -> "PAIR" <+> renderDoc ta <+> renderDoc va <+> renderAnn fa1 <+> renderAnn fa2-    CAR va fa             -> "CAR" <+> renderDoc va <+> renderDoc fa-    CDR va fa             -> "CDR" <+> renderDoc va <+> renderDoc fa-    LEFT ta va fa1 fa2 t  -> "LEFT" <+> renderDoc ta <+> renderDoc va <+> renderAnn fa1 <+> renderAnn fa2 <+> renderDoc t-    RIGHT ta va fa1 fa2 t -> "RIGHT" <+> renderDoc ta <+> renderDoc va <+> renderAnn fa1 <+> renderAnn fa2 <+> renderDoc t-    IF_LEFT x y           -> "IF_LEFT" <+> nest 9 (renderOps x) <$$> spaces 8 <> nest 9 (renderOps y)-    NIL ta va t           -> "NIL" <+> renderDoc ta <+> renderDoc va <+> renderDoc t-    CONS va               -> "CONS" <+> renderDoc va-    IF_CONS x y           -> "IF_CONS" <+> nest 9 (renderOps x) <$$> spaces 8 <> nest 9 (renderOps y)-    SIZE va               -> "SIZE" <+> renderDoc va-    EMPTY_SET ta va t     -> "EMPTY_SET" <+> renderDoc ta <+> renderDoc va <+> renderDoc t-    EMPTY_MAP ta va c t   -> "EMPTY_MAP" <+> renderDoc ta <+> renderDoc va <+> renderDoc c <+> renderDoc t-    MAP va s              -> "MAP" <+> renderDoc va <$$> spaces 4 <> nest 5 (renderOps s)-    ITER s                -> "ITER" <+> nest 6 (renderOps s)-    MEM va                -> "MEM" <+> renderDoc va-    GET va                -> "GET" <+> renderDoc va-    UPDATE                -> "UPDATE"-    IF x y                -> "IF" <+> nest 4 (renderOps x) <$$> spaces 3 <> nest 4 (renderOps y)-    LOOP s                -> "LOOP" <+> nest 6 (renderOps s)-    LOOP_LEFT s           -> "LOOP_LEFT" <+> nest 11 (renderOps s)-    LAMBDA va t r s       -> "LAMBDA" <+> renderDoc va <+> renderDoc t <+> renderDoc r <$$> spaces 7 <> nest 8 (renderOps s)-    EXEC va               -> "EXEC" <+> renderDoc va-    DIP s                 -> "DIP" <+> nest 5 (renderOps s)-    FAILWITH              -> "FAILWITH"-    CAST va t             -> "CAST" <+> renderDoc va <+> renderDoc t-    RENAME va             -> "RENAME" <+> renderDoc va-    PACK va               -> "PACK" <+> renderDoc va-    UNPACK va t           -> "UNPACK" <+> renderDoc va <+> renderDoc t-    CONCAT va             -> "CONCAT" <+> renderDoc va-    SLICE va              -> "SLICE" <+> renderDoc va-    ISNAT va              -> "ISNAT" <+> renderDoc va-    ADD va                -> "ADD" <+> renderDoc va-    SUB va                -> "SUB" <+> renderDoc va-    MUL va                -> "MUL" <+> renderDoc va-    EDIV va               -> "EDIV" <+> renderDoc va-    ABS va                -> "ABS" <+> renderDoc va-    NEG                   -> "NEG"-    LSL va                -> "LSL" <+> renderDoc va-    LSR va                -> "LSR" <+> renderDoc va-    OR  va                -> "OR" <+> renderDoc va-    AND va                -> "AND" <+> renderDoc va-    XOR va                -> "XOR" <+> renderDoc va-    NOT va                -> "NOT" <+> renderDoc va-    COMPARE va            -> "COMPARE" <+> renderDoc va-    EQ va                 -> "EQ" <+> renderDoc va-    NEQ va                -> "NEQ" <+> renderDoc va-    LT va                 -> "LT" <+> renderDoc va-    GT va                 -> "GT" <+> renderDoc va-    LE va                 -> "LE" <+> renderDoc va-    GE va                 -> "GE" <+> renderDoc va-    INT va                -> "INT" <+> renderDoc va-    SELF va               -> "SELF" <+> renderDoc va-    CONTRACT va t         -> "CONTRACT" <+> renderDoc va <+> renderDoc t-    TRANSFER_TOKENS va    -> "TRANSFER_TOKENS" <+> renderDoc va-    SET_DELEGATE va       -> "SET_DELEGATE" <+> renderDoc va-    CREATE_ACCOUNT va1 va2  -> "CREATE_ACCOUNT" <+> renderAnn va1 <+> renderAnn va2-    CREATE_CONTRACT va1 va2 contract ->-      "CREATE_CONTRACT" <+> renderAnn va1 <+> renderAnn va2 <$$> braces (renderDoc contract)-    IMPLICIT_ACCOUNT va   -> "IMPLICIT_ACCOUNT" <+> renderDoc va-    NOW va                -> "NOW" <+> renderDoc va-    AMOUNT va             -> "AMOUNT" <+> renderDoc va-    BALANCE va            -> "BALANCE" <+> renderDoc va-    CHECK_SIGNATURE va    -> "CHECK_SIGNATURE" <+> renderDoc va-    SHA256 va             -> "SHA256" <+> renderDoc va-    SHA512 va             -> "SHA512" <+> renderDoc va-    BLAKE2B va            -> "BLAKE2B" <+> renderDoc va-    HASH_KEY va           -> "HASH_KEY" <+> renderDoc va-    STEPS_TO_QUOTA va     -> "STEPS_TO_QUOTA" <+> renderDoc va-    SOURCE va             -> "SOURCE" <+> renderDoc va-    SENDER va             -> "SENDER" <+> renderDoc va-    ADDRESS va            -> "ADDRESS" <+> renderDoc va+  renderDoc pn = \case+    EXT extInstr            -> renderDoc pn extInstr+    DROP                    -> "DROP"+    DROPN n                 -> "DROP" <+> text (show n)+    DUP va                  -> "DUP" <+> renderAnnot va+    SWAP                    -> "SWAP"+    DIG n                   -> "DIG" <+> text (show n)+    DUG n                   -> "DUG" <+> text (show n)+    PUSH va t v             -> "PUSH" <+> renderAnnot va <+> renderTy t <+> renderDoc needsParens v+    SOME ta va              -> "SOME" <+> renderAnnot ta <+> renderAnnot va+    NONE ta va t            -> "NONE" <+> renderAnnot ta <+> renderAnnot va <+> renderTy t+    UNIT ta va              -> "UNIT" <+> renderAnnot ta <+> renderAnnot va+    IF_NONE x y             -> "IF_NONE" <+> nest 9 (renderOps x) <$$> spaces 8 <> nest 9 (renderOps y)+    PAIR ta va fa1 fa2      -> "PAIR" <+> renderAnnot ta <+> renderAnnot va <+> renderTwoAnnotations fa1 fa2+    CAR va fa               -> "CAR" <+> renderAnnot va <+> renderAnnot fa+    CDR va fa               -> "CDR" <+> renderAnnot va <+> renderAnnot fa+    LEFT ta va fa1 fa2 t    -> "LEFT" <+> renderAnnot ta <+> renderAnnot va <+> renderTwoAnnotations fa1 fa2 <+> renderTy t+    RIGHT ta va fa1 fa2 t   -> "RIGHT" <+> renderAnnot ta <+> renderAnnot va <+> renderTwoAnnotations fa1 fa2 <+> renderTy t+    IF_LEFT x y             -> "IF_LEFT" <+> nest 9 (renderOps x) <$$> spaces 8 <> nest 9 (renderOps y)+    NIL ta va t             -> "NIL" <+> renderAnnot ta <+> renderAnnot va <+> renderTy t+    CONS va                 -> "CONS" <+> renderAnnot va+    IF_CONS x y             -> "IF_CONS" <+> nest 9 (renderOps x) <$$> spaces 8 <> nest 9 (renderOps y)+    SIZE va                 -> "SIZE" <+> renderAnnot va+    EMPTY_SET ta va t       -> "EMPTY_SET" <+> renderAnnot ta <+> renderAnnot va <+> renderComp t+    EMPTY_MAP ta va c t     -> "EMPTY_MAP" <+> renderAnnot ta <+> renderAnnot va <+> renderComp c <+> renderTy t+    EMPTY_BIG_MAP ta va c t -> "EMPTY_BIG_MAP" <+> renderAnnot ta <+> renderAnnot va <+> renderComp c <+> renderTy t+    MAP va s                -> "MAP" <+> renderAnnot va <$$> spaces 4 <> nest 5 (renderOps s)+    ITER s                  -> "ITER" <+> nest 6 (renderOps s)+    MEM va                  -> "MEM" <+> renderAnnot va+    GET va                  -> "GET" <+> renderAnnot va+    UPDATE va               -> "UPDATE" <+> renderAnnot va+    IF x y                  -> "IF" <+> nest 4 (renderOps x) <$$> spaces 3 <> nest 4 (renderOps y)+    LOOP s                  -> "LOOP" <+> nest 6 (renderOps s)+    LOOP_LEFT s             -> "LOOP_LEFT" <+> nest 11 (renderOps s)+    LAMBDA va t r s         -> "LAMBDA" <+> renderAnnot va <+> renderTy t <+> renderTy r <$$> spaces 7 <> nest 8 (renderOps s)+    EXEC va                 -> "EXEC" <+> renderAnnot va+    APPLY va                -> "APPLY" <+> renderAnnot va+    DIP s                   -> "DIP" <+> nest 5 (renderOps s)+    DIPN n s                -> "DIP" <+> text (show n) <> line <> indent (3 + (length $ show @Text n)) (renderOps s)+    FAILWITH                -> "FAILWITH"+    CAST va t               -> "CAST" <+> renderAnnot va <+> renderTy t+    RENAME va               -> "RENAME" <+> renderAnnot va+    PACK va                 -> "PACK" <+> renderAnnot va+    UNPACK va t             -> "UNPACK" <+> renderAnnot va <+> renderTy t+    CONCAT va               -> "CONCAT" <+> renderAnnot va+    SLICE va                -> "SLICE" <+> renderAnnot va+    ISNAT va                -> "ISNAT" <+> renderAnnot va+    ADD va                  -> "ADD" <+> renderAnnot va+    SUB va                  -> "SUB" <+> renderAnnot va+    MUL va                  -> "MUL" <+> renderAnnot va+    EDIV va                 -> "EDIV" <+> renderAnnot va+    ABS va                  -> "ABS" <+> renderAnnot va+    NEG va                  -> "NEG" <+> renderAnnot va+    LSL va                  -> "LSL" <+> renderAnnot va+    LSR va                  -> "LSR" <+> renderAnnot va+    OR  va                  -> "OR" <+> renderAnnot va+    AND va                  -> "AND" <+> renderAnnot va+    XOR va                  -> "XOR" <+> renderAnnot va+    NOT va                  -> "NOT" <+> renderAnnot va+    COMPARE va              -> "COMPARE" <+> renderAnnot va+    EQ va                   -> "EQ" <+> renderAnnot va+    NEQ va                  -> "NEQ" <+> renderAnnot va+    LT va                   -> "LT" <+> renderAnnot va+    GT va                   -> "GT" <+> renderAnnot va+    LE va                   -> "LE" <+> renderAnnot va+    GE va                   -> "GE" <+> renderAnnot va+    INT va                  -> "INT" <+> renderAnnot va+    SELF va                 -> "SELF" <+> renderAnnot va+    CONTRACT va fa t        -> "CONTRACT" <+> renderAnnot va <+> renderAnnot fa <+> renderTy t+    TRANSFER_TOKENS va      -> "TRANSFER_TOKENS" <+> renderAnnot va+    SET_DELEGATE va         -> "SET_DELEGATE" <+> renderAnnot va+    CREATE_CONTRACT va1 va2 contract -> let+      body = enclose space space $ align $ (renderDoc doesntNeedParens contract)+      in "CREATE_CONTRACT" <+> renderTwoAnnotations va1 va2 <$$> (indent 2 $ braces $ body)+    IMPLICIT_ACCOUNT va     -> "IMPLICIT_ACCOUNT" <+> renderAnnot va+    NOW va                  -> "NOW" <+> renderAnnot va+    AMOUNT va               -> "AMOUNT" <+> renderAnnot va+    BALANCE va              -> "BALANCE" <+> renderAnnot va+    CHECK_SIGNATURE va      -> "CHECK_SIGNATURE" <+> renderAnnot va+    SHA256 va               -> "SHA256" <+> renderAnnot va+    SHA512 va               -> "SHA512" <+> renderAnnot va+    BLAKE2B va              -> "BLAKE2B" <+> renderAnnot va+    HASH_KEY va             -> "HASH_KEY" <+> renderAnnot va+    STEPS_TO_QUOTA va       -> "STEPS_TO_QUOTA" <+> renderAnnot va+    SOURCE va               -> "SOURCE" <+> renderAnnot va+    SENDER va               -> "SENDER" <+> renderAnnot va+    ADDRESS va              -> "ADDRESS" <+> renderAnnot va+    CHAIN_ID va             -> "CHAIN_ID" <+> renderAnnot va     where-      renderOps = renderOpsList True+      renderTy = renderDoc @Type needsParens+      renderComp = renderDoc @Comparable needsParens+      renderOps = renderOpsList False+      renderTwoAnnotations ann1 ann2 =+        -- If both annotations are noAnn we don't want to explicitly print them+        if (ann1 /= noAnn || ann2 /= noAnn)+        then renderWEAnn ann1 <+> renderWEAnn ann2+        else renderDoc doesntNeedParens ann1 <+> renderDoc doesntNeedParens ann2 +      renderAnnot :: RenderDoc (Annotation tag) => Annotation tag -> Doc+      renderAnnot = renderDoc @(Annotation _) needsParens+   isRenderable = \case     EXT extInstr -> isRenderable extInstr     _ -> True@@ -294,14 +314,10 @@  -- | Data necessary to originate a contract. data OriginationOperation = OriginationOperation-  { ooManager :: !KeyHash-  -- ^ Manager of the contract.+  { ooOriginator :: !Address+  -- ^ Originator of the contract.   , ooDelegate :: !(Maybe KeyHash)   -- ^ Optional delegate.-  , ooSpendable :: !Bool-  -- ^ Whether the contract is spendable.-  , ooDelegatable :: !Bool-  -- ^ Whether the contract is delegatable.   , ooBalance :: !Mutez   -- ^ Initial balance of the contract.   , ooStorage :: !(Value' ExpandedOp)@@ -322,8 +338,6 @@ -- JSON serialization ---------------------------------------------------------------------------- -instance Aeson.ToJSON Op-instance Aeson.FromJSON Op instance Aeson.ToJSON ExpandedOp instance Aeson.FromJSON ExpandedOp instance Aeson.ToJSON op => Aeson.ToJSON (InstrAbstract op)
src/Michelson/Untyped/Type.hs view
@@ -27,6 +27,16 @@   , tkeyHash   , ttimestamp   , taddress+  , toption+  , tpair+  , tor+  , tyint+  , tynat+  , tyunit+  , tybool+  , typair+  , tyor+  , tyImplicitAccountParam   , isAtomicType   , isKey   , isSignature@@ -45,30 +55,33 @@ import Data.Aeson.TH (defaultOptions, deriveJSON) import Data.Data (Data(..)) import Formatting.Buildable (Buildable(build))-import Text.PrettyPrint.Leijen.Text (Doc, parens, (<+>))+import Prelude hiding ((<$>))+import Text.PrettyPrint.Leijen.Text (Doc, align, softbreak, (<$>), (<+>)) -import Michelson.Printer.Util (RenderDoc(..), buildRenderDoc, wrapInParens)-import Michelson.Untyped.Annotation (Annotation(..), FieldAnn, TypeAnn)+import Michelson.Printer.Util+  (Prettier(..), RenderContext, RenderDoc(..), addParens, buildRenderDoc, doesntNeedParens,+  needsParens, wrapInParens)+import Michelson.Untyped.Annotation (Annotation(..), FieldAnn, TypeAnn, noAnn, renderAnn)  -- Annotated type data Type   = Type T TypeAnn-  | TypeParameter-  -- ^ Implicit Parameter type which can be used in contract code-  | TypeStorage-  -- ^ Implicit Storage type which can be used in contract code   deriving (Eq, Show, Data, Generic)  instance RenderDoc Comparable where-  renderDoc (Comparable ct ta) = renderDoc ct <+> renderDoc ta+  renderDoc np (Comparable ct ta) =+    addParens np $+    renderCT ct <+> renderAnn ta +instance RenderDoc (Prettier Type) where+  renderDoc pn (Prettier w) = case w of+    (Type t ta) -> renderType t False pn (Just ta) Nothing+ instance RenderDoc Type where-  renderDoc (Type t ta) = renderType t (Just ta) Nothing-  renderDoc TypeParameter = "Parameter"-  renderDoc TypeStorage = "Storage"+  renderDoc pn (Type t ta) = renderType t True pn (Just ta) Nothing  instance RenderDoc T where-  renderDoc t = renderType t Nothing Nothing+  renderDoc pn t = renderType t True pn Nothing Nothing  -- Ordering between different kinds of annotations is not significant, -- but ordering among annotations of the same kind is. Annotations@@ -77,68 +90,97 @@ -- these are equivalent -- PAIR :t @my_pair %x %y -- PAIR %x %y :t @my_pair-renderType :: T -> Maybe TypeAnn -> Maybe FieldAnn -> Doc-renderType t mta mfa =-  let rta = case mta of Just ta -> renderDoc ta; Nothing -> ""-      rfa = case mfa of Just fa -> renderDoc fa; Nothing -> ""-      renderer type_ mfa' =-        case type_ of-          Type tt ta -> renderType tt (Just ta) mfa'-          tt -> renderDoc tt+renderType+  :: T+  -> Bool+  -> RenderContext+  -> Maybe TypeAnn+  -> Maybe FieldAnn+  -> Doc+renderType t forceSingleLine pn mta mfa =+  let rta = case mta of Just ta -> renderDoc doesntNeedParens ta; Nothing -> ""+      rfa = case mfa of Just fa -> renderDoc doesntNeedParens fa; Nothing -> ""+      recRenderer (Type tt ta) mfa' =+          renderType tt forceSingleLine needsParens (Just ta) mfa'+      renderBranches d1 d2 =+        if forceSingleLine+        then (d1 <+> d2)+        else align $ softbreak <> (d1 <$> d2)   in   case t of-    Tc ct             -> wrapInParens $ renderDoc ct :| [rta, rfa]-    TKey              -> wrapInParens $ "key"  :| [rta, rfa]-    TUnit             -> wrapInParens $ "unit" :| [rta, rfa]-    TSignature        -> wrapInParens $ "signature" :| [rta, rfa]-    TOperation        -> wrapInParens $ "operation" :| [rta, rfa]-    TOption fa1 (Type t1 ta1) ->-      parens ("option" <+> rta <+> rfa-              <+> renderType t1 (Just ta1) (Just fa1))-    TOption _fa1 t1 ->-      parens ("option" <+> rta <+> rfa <+> renderDoc t1)-    TList (Type t1 ta1)       -> parens ("list" <+> rta <+> rfa <+> renderType t1 (Just ta1) Nothing)-    TList t1                  -> parens ("list" <+> rta <+> rfa <+> renderDoc t1)-    TSet (Comparable ct1 ta1) -> parens ("set" <+> rta <+> rfa <+> renderType (Tc ct1) (Just ta1) Nothing)-    TContract (Type t1 ta1)   -> parens ("contract" <+> rta <+> rfa <+> renderType t1 (Just ta1) Nothing)-    TContract t1              -> parens ("contract" <+> rta <+> rfa <+> renderDoc t1)+    Tc ct             -> wrapInParens pn $ renderCT ct :| [rta, rfa]+    TKey              -> wrapInParens pn $ "key"  :| [rta, rfa]+    TUnit             -> wrapInParens pn $ "unit" :| [rta, rfa]+    TSignature        -> wrapInParens pn $ "signature" :| [rta, rfa]+    TChainId          -> wrapInParens pn $ "chain_id" :| [rta, rfa]+    TOperation        -> wrapInParens pn $ "operation" :| [rta, rfa] +    TOption (Type t1 ta1) ->+      addParens pn $+      "option" <+> rta <+> rfa+               <+> renderType t1 forceSingleLine needsParens (Just ta1) Nothing++    TList (Type t1 ta1)       ->+      addParens pn $+      "list" <+> rta <+> rfa+             <+> renderType t1 forceSingleLine needsParens (Just ta1) Nothing++    TSet (Comparable ct1 ta1) ->+      addParens pn $+      "set" <+> rta <+> rfa+            <+> renderType (Tc ct1) forceSingleLine needsParens (Just ta1) Nothing++    TContract (Type t1 ta1)   ->+      addParens pn $+      "contract" <+> rta <+> rfa+                 <+> renderType t1 forceSingleLine needsParens (Just ta1) Nothing+     TPair fa1 fa2 t1 t2 ->-      parens ("pair" <+> rta <+> rfa-              <+> renderer t1 (Just fa1)-              <+> renderer t2 (Just fa2))+      addParens pn $+        "pair" <+> rta <+> rfa <+>+          (renderBranches+            (recRenderer t1 (Just fa1)) (recRenderer t2 (Just fa2)))      TOr fa1 fa2 t1 t2 ->-      parens ("or" <+> rta <+> rfa-              <+> renderer t1 (Just fa1)-              <+> renderer t2 (Just fa2))+      addParens pn $+        "or" <+> rta <+> rfa <+>+          (renderBranches+            (recRenderer t1 (Just fa1)) (recRenderer t2 (Just fa2)))      TLambda t1 t2 ->-      parens ("lambda" <+> rta <+> rfa-             <+> renderer t1 Nothing-             <+> renderer t2 Nothing)+      addParens pn $+        "lambda" <+> rta <+> rfa <+>+          (renderBranches+            (recRenderer t1 Nothing) (recRenderer t2 Nothing))      TMap (Comparable ct1 ta1) t2 ->-      parens ("map" <+> rta <+> rfa-              <+> (renderType (Tc ct1) (Just ta1) Nothing)-              <+> renderer t2 Nothing)+      addParens pn $+        "map" <+> rta <+> rfa <+>+          (renderBranches+            (renderType (Tc ct1) forceSingleLine needsParens (Just ta1) Nothing)+            (recRenderer t2 Nothing))      TBigMap (Comparable ct1 ta1) t2 ->-      parens ("big_map" <+> rta <+> rfa-              <+> (renderType (Tc ct1) (Just ta1) Nothing)-              <+> renderer t2 Nothing)+      addParens pn $+        "big_map" <+> rta <+> rfa <+>+          (renderBranches+            (renderType (Tc ct1) forceSingleLine needsParens (Just ta1) Nothing)+            (recRenderer t2 Nothing)) +renderCT :: CT -> Doc+renderCT = \case+  CInt       -> "int"+  CNat       -> "nat"+  CString    -> "string"+  CMutez     -> "mutez"+  CBool      -> "bool"+  CKeyHash   -> "key_hash"+  CTimestamp -> "timestamp"+  CBytes     -> "bytes"+  CAddress   -> "address"+ instance RenderDoc CT where-  renderDoc = \case-    CInt       -> "int"-    CNat       -> "nat"-    CString    -> "string"-    CMutez     -> "mutez"-    CBool      -> "bool"-    CKeyHash   -> "key_hash"-    CTimestamp -> "timestamp"-    CBytes     -> "bytes"-    CAddress   -> "address"+  renderDoc _ = renderCT  instance Buildable Type where   build = buildRenderDoc@@ -163,7 +205,8 @@   | TKey   | TUnit   | TSignature-  | TOption FieldAnn Type+  | TChainId+  | TOption Type   | TList Type   | TSet Comparable   | TOperation@@ -195,31 +238,31 @@   build = buildRenderDoc  pattern Tint :: T-pattern Tint <- Tc CInt+pattern Tint = Tc CInt  pattern Tnat :: T-pattern Tnat <- Tc CNat+pattern Tnat = Tc CNat  pattern Tstring :: T-pattern Tstring <- Tc CString+pattern Tstring = Tc CString  pattern Tbytes :: T-pattern Tbytes <- Tc CBytes+pattern Tbytes = Tc CBytes  pattern Tmutez :: T-pattern Tmutez <- Tc CMutez+pattern Tmutez = Tc CMutez  pattern Tbool :: T-pattern Tbool <- Tc CBool+pattern Tbool = Tc CBool  pattern Tkey_hash :: T-pattern Tkey_hash <- Tc CKeyHash+pattern Tkey_hash = Tc CKeyHash  pattern Ttimestamp :: T-pattern Ttimestamp <- Tc CTimestamp+pattern Ttimestamp = Tc CTimestamp  pattern Taddress :: T-pattern Taddress <- Tc CAddress+pattern Taddress = Tc CAddress  tint :: T tint = Tc CInt@@ -247,6 +290,38 @@  taddress :: T taddress = Tc CAddress++toption :: Type -> T+toption t = TOption t++tpair :: Type -> Type -> T+tpair l r = TPair noAnn noAnn l r++tor :: Type -> Type -> T+tor l r = TOr noAnn noAnn l r++tyint :: Type+tyint = Type tint noAnn++tynat :: Type+tynat = Type tnat noAnn++tyunit :: Type+tyunit = Type TUnit noAnn++tybool :: Type+tybool = Type tbool noAnn++typair :: Type -> Type -> Type+typair l r = Type (tpair l r) noAnn++tyor :: Type -> Type -> Type+tyor l r = Type (tor l r) noAnn++-- | For implicit account, which type its parameter seems to have+-- from outside.+tyImplicitAccountParam :: Type+tyImplicitAccountParam = Type TUnit noAnn  isAtomicType :: Type -> Bool isAtomicType t@(Type _ (Annotation "")) =
src/Michelson/Untyped/Value.hs view
@@ -15,9 +15,11 @@ import Data.Data (Data(..)) import Formatting.Buildable (Buildable(build)) import Text.Hex (decodeHex, encodeHex)-import Text.PrettyPrint.Leijen.Text (braces, dquotes, parens, semi, text, textStrict, (<+>))+import Text.PrettyPrint.Leijen.Text+  (Doc, braces, dquotes, enclose, semi, space, text, textStrict, (<+>)) -import Michelson.Printer.Util (RenderDoc(..), buildRenderDoc, renderOps)+import Michelson.Printer.Util+  (RenderDoc(..), addParens, buildRenderDoc, doesntNeedParens, needsParens, renderOps) import Michelson.Text  data Value' op =@@ -52,7 +54,7 @@ unInternalByteString (InternalByteString bs) = bs  instance RenderDoc op => RenderDoc (Value' op) where-  renderDoc =+  renderDoc pn =     \case       ValueNil       -> "{ }"       ValueInt x     -> text . show $ x@@ -61,17 +63,31 @@       ValueUnit      -> "Unit"       ValueTrue      -> "True"       ValueFalse     -> "False"-      ValuePair l r  -> parens $ ("Pair"  <+> renderDoc l <+> renderDoc r)-      ValueLeft l    -> parens $ ("Left"  <+> renderDoc l)-      ValueRight r   -> parens $ ("Right" <+> renderDoc r)-      ValueSome x    -> parens $ ("Some"  <+> renderDoc x)+      ValuePair l r  -> addParens pn $+                        "Pair" <+> renderDoc needsParens l <+> renderDoc needsParens r+      ValueLeft l    -> addParens pn $+                        "Left" <+> renderDoc needsParens l+      ValueRight r   -> addParens pn $+                        "Right" <+> renderDoc needsParens r+      ValueSome x    -> addParens pn $+                        "Some"  <+> renderDoc needsParens x       ValueNone      -> "None"-      ValueSeq xs    -> braces $ mconcat $ (intersperse semi (renderDoc <$> toList xs))-      ValueMap xs    -> braces $ mconcat $ (intersperse semi (renderDoc <$> toList xs))+      ValueSeq xs    -> renderValuesList (renderDoc doesntNeedParens) xs+      ValueMap xs    -> renderValuesList renderElt xs       ValueLambda xs -> renderOps True xs +renderElt :: RenderDoc op => Elt op -> Doc+renderElt (Elt k v) =+   "Elt" <+> renderDoc needsParens k <+> renderDoc needsParens v+ instance RenderDoc op => RenderDoc (Elt op) where-  renderDoc (Elt k v) = "Elt" <+> renderDoc k <+> renderDoc v+  renderDoc _ = renderElt++renderValuesList :: (e -> Doc) -> NonEmpty e -> Doc+renderValuesList renderElem (toList -> es) =+  braces . enclose space space $+    mconcat . intersperse (semi <> space) $+      renderElem <$> es  instance (RenderDoc op) => Buildable (Value' op) where   build = buildRenderDoc
src/Tezos/Address.hs view
@@ -1,15 +1,21 @@ -- | Address in Tezos.  module Tezos.Address-  ( Address (..)+  ( ContractHash (..)+  , Address (..)   , mkKeyAddress+  , detGenKeyAddress   , mkContractAddressRaw+  , mkContractHashRaw    -- * Formatting+  , ParseAddressError (..)+  , ParseContractAddressError   , formatAddress   , mformatAddress   , parseAddress   , unsafeParseAddress+  , unsafeParseContractHash   ) where  import Data.Aeson (FromJSON(..), FromJSONKey, ToJSON(..), ToJSONKey)@@ -24,20 +30,28 @@ import Michelson.Text import Tezos.Crypto +-- TODO: we should probably have a `Hash` type.+-- | Hash of origination command for some contract.+newtype ContractHash = ContractHash ByteString+  deriving (Show, Eq, Ord)+ -- | Data type corresponding to address structure in Tezos. data Address   = KeyAddress !KeyHash   -- ^ `tz` address which is a hash of a public key.-  | ContractAddress !ByteString+  | ContractAddress !ContractHash   -- ^ `KT` address which corresponds to a callable contract.-  -- It's a hash of origination command.-  -- TODO: we should probably have a `Hash` type.   deriving (Show, Eq, Ord)  -- | Smart constructor for 'KeyAddress'. mkKeyAddress :: PublicKey -> Address mkKeyAddress = KeyAddress . hashKey +-- | Deterministically generate a random 'KeyAddress' and discard its+-- secret key.+detGenKeyAddress :: ByteString -> Address+detGenKeyAddress = mkKeyAddress . toPublic . detSecretKey+ -- | Smart constructor for 'ContractAddress'. Its argument is -- serialized origination operation. --@@ -51,17 +65,25 @@ -- function and provide a safer function in 'Michelson.Untyped.Instr'. -- We may reconsider it later. mkContractAddressRaw :: ByteString -> Address-mkContractAddressRaw = ContractAddress . blake2b160 . blake2b160+mkContractAddressRaw = ContractAddress . mkContractHashRaw +-- | Create a dummy 'ContractHash' value.+mkContractHashRaw :: ByteString -> ContractHash+mkContractHashRaw = ContractHash . blake2b160 . blake2b160+ ---------------------------------------------------------------------------- -- Formatting/parsing ---------------------------------------------------------------------------- +formatContractHash :: ContractHash -> Text+formatContractHash (ContractHash bs) =+  encodeBase58Check (contractAddressPrefix <> bs)+ formatAddress :: Address -> Text formatAddress =   \case     KeyAddress h -> formatKeyHash h-    ContractAddress bs -> encodeBase58Check (contractAddressPrefix <> bs)+    ContractAddress h -> formatContractHash h  mformatAddress :: Address -> MText mformatAddress = mkMTextUnsafe . formatAddress@@ -98,7 +120,7 @@   case parseKeyHash addressText of     Left CryptoParseWrongBase58Check -> Left ParseAddressWrongBase58Check     Left keyAddrErr -> first (ParseAddressBothFailed keyAddrErr) $-      parseContractAddress addressText+      ContractAddress <$> parseContractHash addressText     Right keyHash -> Right (KeyAddress keyHash)  -- | Partial version of 'parseAddress' which assumes that the address@@ -122,8 +144,8 @@       ParseContractAddressWrongSize s ->         "Wrong size for a contract address: " <> Buildable.build s -parseContractAddress :: Text -> Either ParseContractAddressError Address-parseContractAddress text =+parseContractHash :: Text -> Either ParseContractAddressError ContractHash+parseContractHash text =   case decodeBase58CheckWithPrefix contractAddressPrefix text of     Left (B58CheckWithPrefixWrongPrefix prefix) ->       Left (ParseContractAddressWrongTag prefix)@@ -131,9 +153,15 @@       Left ParseContractAddressWrongBase58Check     -- We know that the length must be 20.     -- Currently it's hardcoded here, later we'll probably have a `Hash` type.-    Right bs | length bs == 20 -> Right (ContractAddress bs)+    Right bs | length bs == 20 -> Right (ContractHash bs)              | otherwise -> Left $ ParseContractAddressWrongSize (length bs) +-- | Parse a `TK` contract address, fail if address does not match+-- the expected format.+unsafeParseContractHash :: HasCallStack => Text -> ContractHash+unsafeParseContractHash =+  either (error . pretty) id . parseContractHash+ -- It's a magic constant used by Tezos to encode a contract address. -- It was deduced empirically. contractAddressPrefix :: ByteString@@ -143,6 +171,24 @@ -- Aeson instances ---------------------------------------------------------------------------- +instance ToJSON ContractHash where+  toJSON = Aeson.String . formatContractHash+  toEncoding = Aeson.text . formatContractHash++instance ToJSONKey ContractHash where+  toJSONKey = AesonTypes.toJSONKeyText formatContractHash++instance FromJSON ContractHash where+  parseJSON =+    Aeson.withText "ContractHash" $+    either (fail . pretty) pure . parseContractHash++instance FromJSONKey ContractHash where+  fromJSONKey =+    AesonTypes.FromJSONKeyTextParser+      (either (fail . pretty) pure . parseContractHash)++ instance ToJSON Address where   toJSON = Aeson.String . formatAddress   toEncoding = Aeson.text . formatAddress@@ -168,4 +214,4 @@   arbitrary = oneof [genKeyAddress, genContractAddress]     where       genKeyAddress = KeyAddress <$> arbitrary-      genContractAddress = ContractAddress . BS.pack <$> vector 20+      genContractAddress = ContractAddress . ContractHash . BS.pack <$> vector 20
src/Tezos/Core.hs view
@@ -25,17 +25,42 @@   , timestampPlusSeconds   , formatTimestamp   , parseTimestamp+  , timestampQuote   , getCurrentTime+  , farFuture+  , farPast++    -- * ChainId+  , ChainId (..)+  , mkChainId+  , mkChainIdUnsafe+  , dummyChainId+  , formatChainId+  , mformatChainId+  , parseChainId+  , chainIdLength   ) where +import Data.Aeson (FromJSON(..), ToJSON(..))+import qualified Data.Aeson as Aeson import Data.Aeson.TH (defaultOptions, deriveJSON)+import qualified Data.ByteString as BS import Data.Data (Data(..))+import qualified Data.Text as T import Data.Time.Clock (UTCTime) import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime, posixSecondsToUTCTime, utcTimeToPOSIXSeconds)-import Data.Time.LocalTime (utc, utcToZonedTime, zonedTimeToUTC)-import Data.Time.RFC3339 (formatTimeRFC3339, parseTimeRFC3339)+import Data.Time.Format (defaultTimeLocale, parseTimeM)+import Data.Time.LocalTime (utc, utcToZonedTime)+import Data.Time.RFC3339 (formatTimeRFC3339)+import Fmt (fmt, hexF, pretty) import Formatting.Buildable (Buildable(build))+import qualified Language.Haskell.TH.Quote as TH+import Language.Haskell.TH.Syntax (liftData)+import Test.QuickCheck (Arbitrary(..), vector) +import Michelson.Text+import Tezos.Crypto+ ---------------------------------------------------------------------------- -- Mutez ----------------------------------------------------------------------------@@ -140,7 +165,7 @@ timestampToSeconds = round . unTimestamp {-# INLINE timestampToSeconds #-} -timestampFromSeconds :: Integral a => a -> Timestamp+timestampFromSeconds :: Integer -> Timestamp timestampFromSeconds = Timestamp . fromIntegral {-# INLINE timestampFromSeconds #-} @@ -154,6 +179,8 @@  -- | Display timestamp in human-readable way as used by Michelson. -- Uses UTC timezone, though maybe we should take it as an argument.+--+-- NB: this will render timestamp with up to seconds precision. formatTimestamp :: Timestamp -> Text formatTimestamp =   formatTimeRFC3339 . utcToZonedTime utc . posixSecondsToUTCTime . unTimestamp@@ -163,15 +190,143 @@  -- | Parse textual representation of 'Timestamp'. parseTimestamp :: Text -> Maybe Timestamp-parseTimestamp = fmap (timestampFromUTCTime . zonedTimeToUTC) . parseTimeRFC3339+parseTimestamp t+  -- `parseTimeM` does not allow to match on a single whitespace exclusively+  | T.isInfixOf "  " t = Nothing+  | otherwise = fmap timestampFromUTCTime . asum $ map parse formatsRFC3339+  where+    parse :: Text -> Maybe UTCTime+    parse frmt = parseTimeM False defaultTimeLocale (toString frmt) (toString t) +    formatsRFC3339 :: [Text]+    formatsRFC3339 = do+      divider <- ["T", " "]+      fraction <- ["%Q", ""]+      zone <- ["Z", "%z"]+      return $ "%-Y-%m-%d" <> divider <> "%T" <> fraction <> zone++-- | Quote a value of type 'Timestamp' in @yyyy-mm-ddThh:mm:ss[.sss]Z@ format.+--+-- >>> formatTimestamp [timestampQuote| 2019-02-21T16:54:12.2344523Z |]+-- "2019-02-21T16:54:12Z"+--+-- Inspired by 'time-quote' library.+timestampQuote :: TH.QuasiQuoter+timestampQuote =+  TH.QuasiQuoter+  { quoteExp = \str ->+      case parseTimestamp . T.strip $ toText str of+        Nothing -> fail "Invalid timestamp, \+                        \example of valid value: `2019-02-21T16:54:12.2344523Z`"+        Just ts -> liftData ts+  , quotePat = \_ -> fail "timestampQuote: cannot quote pattern!"+  , quoteType = \_ -> fail "timestampQuote: cannot quote type!"+  , quoteDec = \_ -> fail "timestampQuote: cannot quote declaration!"+  }+ -- | Return current time as 'Timestamp'. getCurrentTime :: IO Timestamp getCurrentTime = Timestamp <$> getPOSIXTime +-- | Timestamp which is always greater than result of 'getCurrentTime'.+farFuture :: Timestamp+farFuture = timestampFromSeconds 1e12  -- 33658-09-27T01:46:40Z++-- | Timestamp which is always less than result of 'getCurrentTime'.+farPast :: Timestamp+farPast = timestampFromSeconds 0+ ----------------------------------------------------------------------------+-- Chain ID+----------------------------------------------------------------------------++{- Chain id in Tezos sources:+* https://gitlab.com/tezos/tezos/blob/de5c80b360aa396114be92a3a2e2ff2087190a61/src/lib_crypto/chain_id.ml+-}++-- | Identifier of a network (babylonnet, mainnet, test network or other).+-- Evaluated as hash of the genesis block.+--+-- The only operation supported for this type is packing.+-- Use case: multisig contract, for instance, now includes chain ID into+-- signed data "in order to add extra replay protection between the main+-- chain and the test chain".+newtype ChainId = ChainIdUnsafe { unChainId :: ByteString }+  deriving (Show, Eq)++-- | Construct chain ID from raw bytes.+mkChainId :: ByteString -> Maybe ChainId+mkChainId bs =+  guard (length bs == chainIdLength) $> ChainIdUnsafe bs++-- | Construct chain ID from raw bytes or fail otherwise.+-- Expects exactly 4 bytes.+mkChainIdUnsafe :: HasCallStack => ByteString -> ChainId+mkChainIdUnsafe = fromMaybe (error "Bad chain id") . mkChainId++-- | Identifier of a pseudo network.+dummyChainId :: ChainId+dummyChainId = ChainIdUnsafe "\0\0\0\0"++-- | Pretty print 'ChainId' as it is displayed e.g. in @./babylonnet.sh head@ call.+--+-- Example of produced value: "NetXUdfLh6Gm88t".+formatChainId :: ChainId -> Text+formatChainId (unChainId -> bs) = encodeBase58Check (chainIdPrefix <> bs)++mformatChainId :: ChainId -> MText+mformatChainId = mkMTextUnsafe . formatChainId++instance Buildable ChainId where+  build = build . formatChainId++data ParseChainIdError+  = ParseChainIdWrongBase58Check+  | ParseChainIdWrongTag !ByteString+  | ParseChainIdWrongSize !Int+  deriving (Show, Eq)++instance Buildable ParseChainIdError where+  build =+    \case+      ParseChainIdWrongBase58Check ->+        "Wrong base58check format"+      ParseChainIdWrongTag tag ->+        "Wrong tag for a chain id: " <> fmt (hexF tag)+      ParseChainIdWrongSize s ->+        "Wrong size for a chain id: " <> build s++parseChainId :: Text -> Either ParseChainIdError ChainId+parseChainId text =+  case decodeBase58CheckWithPrefix chainIdPrefix text of+    Left (B58CheckWithPrefixWrongPrefix prefix) ->+      Left (ParseChainIdWrongTag prefix)+    Left B58CheckWithPrefixWrongEncoding ->+      Left ParseChainIdWrongBase58Check+    Right bs -> case mkChainId bs of+      Just ci -> Right ci+      Nothing -> Left $ ParseChainIdWrongSize (length bs)++chainIdLength :: Int+chainIdLength = 4++-- | It's a magic constant used by Tezos to encode a chain ID.+-- Corresponds to "Net" part.+chainIdPrefix :: ByteString+chainIdPrefix = "\87\82\0"++instance Arbitrary ChainId where+  arbitrary = ChainIdUnsafe . BS.pack <$> (vector 4)++---------------------------------------------------------------------------- -- JSON ----------------------------------------------------------------------------  deriveJSON defaultOptions ''Mutez deriveJSON defaultOptions ''Timestamp++instance ToJSON ChainId where+  toJSON = Aeson.String . formatChainId+instance FromJSON ChainId where+  parseJSON = Aeson.withText "chain id" $+    either (fail . pretty) pure . parseChainId
src/Tezos/Crypto.hs view
@@ -1,33 +1,65 @@+{-# LANGUAGE DerivingStrategies #-}+ -- | Cryptographic primitives used in Tezos.+--+-- WARNING: some functions may be vulnerable to timing attacks.+-- Also, this code was not reviewed by cryptography/security experts.+-- Do not use it with secret keys that have some value.+-- We provide 'SecretKey' type and (limited) signing functionality only+-- for testing.+-- If you need to sign something in production, use something else+-- (e. g. `tezos-client`).+--+-- Tezos supports 3 cryptographic curves that are denoted by the+-- number after tz in the public key hash: tz1, tz2 or tz3.+-- • tz1 — ed25519+-- • tz2 — secp256k1+-- • tz3 — P256+-- We have Tezos.Crypto.Curve module for each of these curves.+-- They expose very similar functionality and their main purpose is to hide+-- implementation details for each curve as well as some other specifics (e. g.+-- prefixes that are used for human-readable representation).+--+-- This module serves two purposes:+-- 1. It is an umbrella module that re-exports some stuff from other modules.+-- 2. Michelson types such as `key` and `signature` may store primitive of any+-- curve, so we need "union" types in Haskell as well.+--+-- During conversion to human-readable representation usually some magical+-- prefix is used. They have been found in source code in some repos (e. g.+-- <https://gitlab.com/tezos/tezos/blob/c52ee69231c5ae4d9cec1f3c8aba0c3573922e2a/src/lib_crypto/base58.ml>)+-- and checked manually. Existing tests confirm they are correct.  module Tezos.Crypto   ( -- * Cryptographic primitive types     PublicKey (..)   , SecretKey   , Signature (..)+  , KeyHashTag (..)   , KeyHash (..)++  -- * Public/secret key functions   , detSecretKey   , toPublic +  -- * Signature+  , signatureToBytes+  , mkSignature+  , signatureLengthBytes+  , checkSignature+   -- * Formatting   , CryptoParseError (..)   , formatPublicKey   , mformatPublicKey   , parsePublicKey-  , mkPublicKey-  , formatSecretKey-  , parseSecretKey   , formatSignature   , mformatSignature   , parseSignature-  , mkSignature   , formatKeyHash   , mformatKeyHash   , parseKeyHash--  -- * Signing-  , sign-  , checkSignature+  , keyHashLengthBytes    -- * Hashing   , hashKey@@ -43,194 +75,238 @@   , decodeBase58CheckWithPrefix   ) where -import Crypto.Error (CryptoError, CryptoFailable(..), eitherCryptoError)-import Crypto.Hash (Blake2b_160, Blake2b_256, Digest, SHA256, SHA512, hash)-import Crypto.Number.Serialize (os2ip)-import qualified Crypto.PubKey.Ed25519 as Ed25519-import Crypto.Random (drgNewSeed, seedFromInteger, withDRG) import Data.Aeson (FromJSON(..), ToJSON(..)) import qualified Data.Aeson as Aeson import qualified Data.Aeson.Encoding as Aeson-import Data.ByteArray (ByteArrayAccess)-import qualified Data.ByteArray as ByteArray+import qualified Data.ByteArray as BA import qualified Data.ByteString as BS-import qualified Data.ByteString.Base58 as Base58-import Data.Coerce (coerce)-import Fmt (fmt, hexF, pretty)-import qualified Formatting.Buildable as Buildable-import Test.QuickCheck (Arbitrary(..), vector)+import Fmt (Buildable, build, pretty)+import Test.QuickCheck (Arbitrary(..), elements, oneof)  import Michelson.Text+import qualified Tezos.Crypto.Ed25519 as Ed25519+import Tezos.Crypto.Hash+import qualified Tezos.Crypto.P256 as P256+import qualified Tezos.Crypto.Secp256k1 as Secp256k1+import Tezos.Crypto.Util  ---------------------------------------------------------------------------- -- Types, instances, conversions ---------------------------------------------------------------------------- --- | ED25519 public cryptographic key.-newtype PublicKey = PublicKey-  { unPublicKey :: Ed25519.PublicKey-  } deriving (Show, Eq)+-- | Public cryptographic key used by Tezos.+-- There are three cryptographic curves each represented by its own constructor.+data PublicKey+  = PublicKeyEd25519 !Ed25519.PublicKey+  -- ^ Public key that uses the ed25519 cryptographic curve.+  | PublicKeySecp256k1 !Secp256k1.PublicKey+  -- ^ Public key that uses the secp256k1 cryptographic curve.+  | PublicKeyP256 !P256.PublicKey+  -- ^ Public key that uses the NIST P-256 cryptographic curve.+  deriving stock (Show, Eq)  instance Arbitrary PublicKey where   arbitrary = toPublic <$> arbitrary --- | ED25519 secret cryptographic key.-newtype SecretKey = SecretKey-  { unSecretKey :: Ed25519.SecretKey-  } deriving (Show, Eq)+-- | Secret cryptographic key used by Tezos.+-- Constructors correspond to 'PublicKey' constructors.+data SecretKey+  = SecretKeyEd25519 !Ed25519.SecretKey+  -- ^ Secret key that uses the ed25519 cryptographic curve.+  | SecretKeySecp256k1 !Secp256k1.SecretKey+  -- ^ Secret key that uses the secp256k1 cryptographic curve.+  | SecretKeyP256 !P256.SecretKey+  -- ^ Secret key that uses the NIST P-256 cryptographic curve.+  deriving stock (Show, Eq)  -- | Deterministicaly generate a secret key from seed.-detSecretKey :: ByteString -> SecretKey-detSecretKey seed =-  let chachaSeed = drgNewSeed . seedFromInteger . os2ip $ seed-      (sk, _) = withDRG chachaSeed Ed25519.generateSecretKey-  in SecretKey sk+-- Type of the key depends on seed length.+detSecretKey :: HasCallStack => ByteString -> SecretKey+detSecretKey seed = seed & case (length seed + 2) `mod` 3 of+  0 -> SecretKeyEd25519 . Ed25519.detSecretKey+  1 -> SecretKeySecp256k1 . Secp256k1.detSecretKey+  2 -> SecretKeyP256 . P256.detSecretKey+  _ -> error "detSecretKey: unexpected happened"  instance Arbitrary SecretKey where-  arbitrary = detSecretKey . BS.pack <$> vector 32+  arbitrary = oneof+    [ SecretKeyEd25519 <$> arbitrary+    , SecretKeySecp256k1 <$> arbitrary+    , SecretKeyP256 <$> arbitrary+    ]  -- | Create a public key from a secret key. toPublic :: SecretKey -> PublicKey-toPublic = PublicKey . Ed25519.toPublic . unSecretKey+toPublic = \case+  SecretKeyEd25519 sk -> PublicKeyEd25519 . Ed25519.toPublic $ sk+  SecretKeySecp256k1 sk -> PublicKeySecp256k1 . Secp256k1.toPublic $ sk+  SecretKeyP256 sk -> PublicKeyP256 . P256.toPublic $ sk --- | ED25519 cryptographic signature.-newtype Signature = Signature-  { unSignature :: Ed25519.Signature-  } deriving (Show, Eq)+-- | Cryptographic signatures used by Tezos.+-- Constructors correspond to 'PublicKey' constructors.+--+-- Tezos distinguishes signatures for different curves.+-- For instance, ed25519 signatures and secp256k1 signatures+-- are printed differently (have different prefix).+-- However, signatures are packed without information about the+-- curve. For this purpose there is a generic signature which+-- only stores bytes and doesn't carry information about the curve.+-- Apparently unpacking from bytes always produces such signature.+-- Unpacking from string produces a signature with curve information.+data Signature+  = SignatureEd25519 !Ed25519.Signature+  -- ^ Signature that uses the ed25519 cryptographic curve.+  | SignatureSecp256k1 !Secp256k1.Signature+  -- ^ Siganture that uses the secp256k1 cryptographic curve.+  | SignatureP256 P256.Signature+  -- ^ Signature that uses the NIST P-256 cryptographic curve.+  | SignatureGeneric !ByteString+  -- ^ Generic signature for which curve is unknown.+  deriving stock (Show) -instance Arbitrary Signature where-  arbitrary = sign <$> arbitrary <*> (encodeUtf8 @String <$> arbitrary)+-- This instance slightly differs from the default one. If one+-- signature is generic and the other one is not, they still may be+-- equal if they have the same byte representation.+-- With default instance packing a signature and unpacking it would produce+-- a different (with respect to 'Eq') signature which is inconvenient.+instance Eq Signature where+  sig1 == sig2 = case (sig1, sig2) of+    (SignatureGeneric bytes1, SignatureGeneric bytes2) -> bytes1 == bytes2+    (SignatureGeneric bytes1, SignatureEd25519 (Ed25519.signatureToBytes -> bytes2)) ->+      bytes1 == bytes2+    (SignatureGeneric bytes1, SignatureSecp256k1 (Secp256k1.signatureToBytes -> bytes2)) ->+      bytes1 == bytes2+    (SignatureGeneric bytes1, SignatureP256 (P256.signatureToBytes -> bytes2)) ->+      bytes1 == bytes2 --- | b58check of a public key.-newtype KeyHash = KeyHash-  { unKeyHash :: ByteString-  } deriving (Show, Eq, Ord)+    (_, SignatureGeneric {}) -> sig2 == sig1 -instance Arbitrary KeyHash where-  arbitrary = hashKey <$> arbitrary+    (SignatureEd25519 s1, SignatureEd25519 s2) -> s1 == s2+    (SignatureEd25519 {}, _) -> False +    (SignatureSecp256k1 s1, SignatureSecp256k1 s2) -> s1 == s2+    (SignatureSecp256k1 {}, _) -> False++    (SignatureP256 s1, SignatureP256 s2) -> s1 == s2+    (SignatureP256 {}, _) -> False++instance Arbitrary Signature where+  arbitrary = oneof+    [ SignatureEd25519 <$> arbitrary+    , SignatureSecp256k1 <$> arbitrary+    , SignatureP256 <$> arbitrary+    , SignatureGeneric . BS.replicate signatureLengthBytes <$> arbitrary+    ]+ ------------------------------------------------------------------------------- Magic bytes------ These magic bytes were deduced empirically by taking sample data--- (public and secret keys, signatures, etc.), decoding it and--- noticing that all of them have the same start bytes.--- Tests prove that they are valid (if they were invalid, parse* functions--- would return some crypto primitive for which underlying crypto would--- work differently).+-- Signature ---------------------------------------------------------------------------- -publicKeyTag :: ByteString-publicKeyTag = "\13\15\37\217"+-- | Convert a 'Signature' to raw bytes.+signatureToBytes :: BA.ByteArray ba => Signature -> ba+signatureToBytes = \case+  SignatureEd25519 sig -> Ed25519.signatureToBytes sig+  SignatureSecp256k1 sig -> Secp256k1.signatureToBytes sig+  SignatureP256 sig -> P256.signatureToBytes sig+  SignatureGeneric bytes -> BA.convert bytes -secretKeyTag :: ByteString-secretKeyTag = "\13\15\58\7"+-- | Make a 'Signature' from raw bytes.+-- Can return only generic signature.+mkSignature :: BA.ByteArray ba => ba -> Maybe Signature+mkSignature ba =+  SignatureGeneric (BA.convert ba) <$ guard (l == signatureLengthBytes)+  where+    l = BA.length ba -signatureTag :: ByteString-signatureTag = "\9\245\205\134\18"+-- Apparently Tezos relies on the fact that in all schemes signature+-- size is 64 bytes, so it also has generic signature and always reads+-- 64 bytes during unpack.+-- So we can have one 'signatureLengthBytes' and do not have to+-- distinguish between curves.+-- However, we still have such a check here just in case as a precaution.+signatureLengthBytes :: HasCallStack => Integral n => n+signatureLengthBytes+  | all is64+    [ Ed25519.signatureLengthBytes+    , P256.signatureLengthBytes+    , Secp256k1.signatureLengthBytes+    ] = 64+  | otherwise =+    error "Apparently our understanding of signatures in Tezos is broken"+  where+    is64 :: Int -> Bool+    is64 = (== 64) -keyHashTag :: ByteString-keyHashTag = "\6\161\159"+genericSignatureTag :: ByteString+genericSignatureTag = "\004\130\043" +-- | Check that a sequence of bytes has been signed with a given key.+-- TODO (#18) consider generic signature here as well.+checkSignature :: PublicKey -> Signature -> ByteString -> Bool+checkSignature pk0 sig0 bytes =+  case (pk0, sig0) of+    (PublicKeyEd25519 pk, SignatureEd25519 sig) ->+      Ed25519.checkSignature pk sig bytes+    (PublicKeySecp256k1 pk, SignatureSecp256k1 sig) ->+      Secp256k1.checkSignature pk sig bytes+    (PublicKeyP256 pk, SignatureP256 sig) ->+      P256.checkSignature pk sig bytes+    _ -> False+ ---------------------------------------------------------------------------- -- Formatting ---------------------------------------------------------------------------- --- | Error that can happen during parsing of cryptographic primitive types.-data CryptoParseError-  = CryptoParseWrongBase58Check-  | CryptoParseWrongTag !ByteString-  | CryptoParseCryptoError CryptoError-  deriving (Show, Eq)--instance Buildable.Buildable CryptoParseError where-  build =-    \case-      CryptoParseWrongBase58Check -> "Wrong base58check encoding of bytes"-      CryptoParseWrongTag tag -> "Prefix is wrong tag: " <> fmt (hexF tag)-      CryptoParseCryptoError err ->-        "Cryptographic library reported an error: " <>-        Buildable.build (displayException err)- formatPublicKey :: PublicKey -> Text-formatPublicKey = formatImpl publicKeyTag . unPublicKey+formatPublicKey = \case+  PublicKeyEd25519 pk -> Ed25519.formatPublicKey pk+  PublicKeySecp256k1 pk -> Secp256k1.formatPublicKey pk+  PublicKeyP256 pk -> P256.formatPublicKey pk  mformatPublicKey :: PublicKey -> MText mformatPublicKey = mkMTextUnsafe . formatPublicKey -instance Buildable.Buildable PublicKey where-  build = Buildable.build . formatPublicKey+instance Buildable PublicKey where+  build = build . formatPublicKey  parsePublicKey :: Text -> Either CryptoParseError PublicKey-parsePublicKey = parseImpl publicKeyTag Ed25519.publicKey--mkPublicKey :: ByteArrayAccess ba => ba -> Either Text PublicKey-mkPublicKey ba =-  case Ed25519.publicKey ba of-    CryptoPassed k -> Right (PublicKey k)-    CryptoFailed e -> Left (show e)--formatSecretKey :: SecretKey -> Text-formatSecretKey = formatImpl secretKeyTag . unSecretKey--instance Buildable.Buildable SecretKey where-  build = Buildable.build . formatSecretKey--parseSecretKey :: Text -> Either CryptoParseError SecretKey-parseSecretKey = parseImpl secretKeyTag Ed25519.secretKey+parsePublicKey txt =+  firstRight $ map ($ txt)+    ( fmap PublicKeyEd25519 . Ed25519.parsePublicKey :|+    [ fmap PublicKeySecp256k1 . Secp256k1.parsePublicKey+    , fmap PublicKeyP256 . P256.parsePublicKey+    ])  formatSignature :: Signature -> Text-formatSignature = formatImpl signatureTag . unSignature+formatSignature = \case+  SignatureEd25519 sig -> Ed25519.formatSignature sig+  SignatureSecp256k1 sig -> Secp256k1.formatSignature sig+  SignatureP256 sig -> P256.formatSignature sig+  SignatureGeneric sig -> formatImpl genericSignatureTag sig  mformatSignature :: Signature -> MText mformatSignature = mkMTextUnsafe . formatSignature -instance Buildable.Buildable Signature where-  build = Buildable.build . formatSignature+instance Buildable Signature where+  build = build . formatSignature  parseSignature :: Text -> Either CryptoParseError Signature-parseSignature = parseImpl signatureTag Ed25519.signature--mkSignature :: ByteArrayAccess ba => ba -> Either Text Signature-mkSignature ba =-  case Ed25519.signature ba of-    CryptoPassed s -> Right (Signature s)-    CryptoFailed e -> Left (show e)--formatKeyHash :: KeyHash -> Text-formatKeyHash = formatImpl keyHashTag . unKeyHash--mformatKeyHash :: KeyHash -> MText-mformatKeyHash = mkMTextUnsafe . formatKeyHash--instance Buildable.Buildable KeyHash where-  build = Buildable.build . formatKeyHash--parseKeyHash :: Text -> Either CryptoParseError KeyHash-parseKeyHash = parseImpl keyHashTag pure--formatImpl :: ByteArray.ByteArrayAccess x => ByteString -> x -> Text-formatImpl tag = encodeBase58Check . mappend tag . ByteArray.convert--parseImpl-  :: Coercible x res-  => ByteString-  -> (ByteString -> CryptoFailable x)-  -> Text-  -> Either CryptoParseError res-parseImpl expectedTag constructor text = do-  let convertErr :: B58CheckWithPrefixError -> CryptoParseError-      convertErr =-        \case B58CheckWithPrefixWrongPrefix prefix -> CryptoParseWrongTag prefix-              B58CheckWithPrefixWrongEncoding -> CryptoParseWrongBase58Check-  payload <- first convertErr $ decodeBase58CheckWithPrefix expectedTag text-  bimap CryptoParseCryptoError coerce $-    eitherCryptoError $ constructor payload+parseSignature txt =+  firstRight $ map ($ txt)+    ( fmap SignatureEd25519 . Ed25519.parseSignature :|+    [ fmap SignatureSecp256k1 . Secp256k1.parseSignature+    , fmap SignatureP256 . P256.parseSignature+    , parseImpl genericSignatureTag (pure . SignatureGeneric)+    ])  ---------------------------------------------------------------------------- -- JSON encoding/decoding ---------------------------------------------------------------------------- +-- If you ever need these instances for any particular 'PublicKey' or+-- 'Signature', you can define them in respective modules the same+-- way.+ instance ToJSON PublicKey where   toJSON = Aeson.String . formatPublicKey   toEncoding = Aeson.text . formatPublicKey@@ -259,91 +335,66 @@     either (fail . pretty) pure . parseKeyHash  ------------------------------------------------------------------------------- Signing--------------------------------------------------------------------------------- | Sign a message using the secret key.-sign :: SecretKey -> ByteString -> Signature-sign sk =-  Signature .-  Ed25519.sign (unSecretKey sk) (unPublicKey (toPublic sk)) . blake2b---- | Check that a sequence of bytes has been signed with a given key.-checkSignature :: PublicKey -> Signature -> ByteString -> Bool-checkSignature (PublicKey pk) (Signature sig) bytes =-  Ed25519.verify pk (blake2b bytes) sig--------------------------------------------------------------------------------- Hashing+-- KeyHash ---------------------------------------------------------------------------- --- | Compute the b58check of a public key hash.-hashKey :: PublicKey -> KeyHash-hashKey (PublicKey pk) =-  KeyHash (fromDigest @Blake2b_160 $ hash @ByteString $ ByteArray.convert pk)+-- | Which curve was used for the hashed public key inside 'KeyHash'.+data KeyHashTag+  = KeyHashEd25519+  | KeyHashSecp256k1+  | KeyHashP256+  deriving stock (Show, Eq, Ord, Bounded, Enum) --- | Compute a cryptographic hash of a bytestring using the--- Blake2b_256 cryptographic hash function. It's used by the BLAKE2B--- instruction in Michelson.-blake2b :: ByteString -> ByteString-blake2b = fromDigest @Blake2b_256 . hash+instance Arbitrary KeyHashTag where+  arbitrary = elements [minBound .. ] --- | Compute a cryptographic hash of a bytestring using the--- Blake2b_160 cryptographic hash function.-blake2b160 :: ByteString -> ByteString-blake2b160 = fromDigest @Blake2b_160 . hash+-- | Blake2b_160 hash of a public key.+data KeyHash = KeyHash+  { khTag :: KeyHashTag+  -- ^ We store which curve was used because it affects formatting.+  , khBytes :: ByteString+  -- ^ Hash itself.+  } deriving (Show, Eq, Ord) --- | Compute a cryptographic hash of a bytestring using the--- Sha256 cryptographic hash function.-sha256 :: ByteString -> ByteString-sha256 = fromDigest @SHA256 . hash+-- | Length of key hash in bytes (only hash itself, no tags, checksums+-- or anything).+keyHashLengthBytes :: Integral n => n+keyHashLengthBytes = 20 --- | Compute a cryptographic hash of a bytestring using the--- Sha512 cryptographic hash function.-sha512 :: ByteString -> ByteString-sha512 = fromDigest @SHA512 . hash+instance Arbitrary KeyHash where+  arbitrary = hashKey <$> arbitrary -fromDigest :: forall a. Digest a -> ByteString-fromDigest = ByteArray.convert+-- | Compute the b58check of a public key hash.+hashKey :: PublicKey -> KeyHash+hashKey =+  \case+    PublicKeyEd25519 pk ->+      KeyHash KeyHashEd25519 (blake2b160 $ Ed25519.publicKeyToBytes pk)+    PublicKeySecp256k1 pk ->+      KeyHash KeyHashSecp256k1 (blake2b160 $ Secp256k1.publicKeyToBytes pk)+    PublicKeyP256 pk ->+      KeyHash KeyHashP256 (blake2b160 $ P256.publicKeyToBytes pk) -------------------------------------------------------------------------------- Utility functions-----------------------------------------------------------------------------+formatKeyHash :: KeyHash -> Text+formatKeyHash (KeyHash tag bytes) = formatImpl (keyHashTagBytes tag) bytes --- | Encode a bytestring in Base58Check format.-encodeBase58Check :: ByteString -> Text-encodeBase58Check =-  decodeUtf8 . Base58.encodeBase58 Base58.bitcoinAlphabet . withCheckSum-  where-    withCheckSum :: ByteString -> ByteString-    withCheckSum bs = bs <> checkSum bs+mformatKeyHash :: KeyHash -> MText+mformatKeyHash = mkMTextUnsafe . formatKeyHash --- | Decode a bytestring from Base58Check format.-decodeBase58Check :: Text -> Maybe ByteString-decodeBase58Check text = do-  bytes <- Base58.decodeBase58 Base58.bitcoinAlphabet (encodeUtf8 text)-  let (payload, chk) = BS.splitAt (length bytes - 4) bytes-  guard $ chk == checkSum payload-  return payload+instance Buildable KeyHash where+  build = build . formatKeyHash -checkSum :: ByteString -> ByteString-checkSum = BS.take 4 . (sha256 . sha256)+parseKeyHash :: Text -> Either CryptoParseError KeyHash+parseKeyHash txt =+  let+    parse :: KeyHashTag -> Either CryptoParseError KeyHash+    parse tag = KeyHash tag <$> parseImpl (keyHashTagBytes tag) pure txt -data B58CheckWithPrefixError-  = B58CheckWithPrefixWrongPrefix ByteString-  | B58CheckWithPrefixWrongEncoding-  deriving (Show)+  in firstRight $ map parse $ minBound :| [succ minBound ..] --- | Parse a base58check encoded value expecting some prefix. If the--- actual prefix matches the expected one, it's stripped of and the--- resulting payload is returned.-decodeBase58CheckWithPrefix ::-     ByteString -> Text -> Either B58CheckWithPrefixError ByteString-decodeBase58CheckWithPrefix prefix text =-  case decodeBase58Check text of-    Nothing -> Left B58CheckWithPrefixWrongEncoding-    Just bs ->-      let (actualPrefix, payload) = BS.splitAt (length prefix) bs-       in if actualPrefix == prefix-          then Right payload-          else Left (B58CheckWithPrefixWrongPrefix actualPrefix)+keyHashTagBytes :: KeyHashTag -> ByteString+keyHashTagBytes =+  \case+    KeyHashEd25519 -> "\006\161\159"+    KeyHashSecp256k1 -> "\006\161\161"+    KeyHashP256 -> "\006\161\164"
+ src/Tezos/Crypto/Ed25519.hs view
@@ -0,0 +1,172 @@+{-# LANGUAGE DerivingStrategies #-}++-- | Ed25519 cryptographic primitives.++module Tezos.Crypto.Ed25519+  ( -- * Cryptographic primitive types+    PublicKey (..)+  , SecretKey+  , Signature (..)+  , detSecretKey+  , toPublic++  -- * Raw bytes (no checksums, tags or anything)+  , publicKeyToBytes+  , mkPublicKey+  , publicKeyLengthBytes+  , signatureToBytes+  , mkSignature+  , signatureLengthBytes++  -- * Formatting and parsing+  , formatPublicKey+  , mformatPublicKey+  , parsePublicKey+  , formatSecretKey+  , formatSignature+  , mformatSignature+  , parseSignature++  -- * Signing+  , sign+  , checkSignature+  ) where++import Crypto.Error (onCryptoFailure)+import qualified Crypto.PubKey.Ed25519 as Ed25519+import Data.ByteArray (ByteArray, ByteArrayAccess, convert)+import qualified Data.ByteString as BS+import Fmt (Buildable, build)+import Test.QuickCheck (Arbitrary(..), vector)++import Michelson.Text+import Tezos.Crypto.Hash+import Tezos.Crypto.Util++----------------------------------------------------------------------------+-- Types, instances, conversions+----------------------------------------------------------------------------++-- | ED25519 public cryptographic key.+newtype PublicKey = PublicKey+  { unPublicKey :: Ed25519.PublicKey+  } deriving stock (Show, Eq)++instance Arbitrary PublicKey where+  arbitrary = toPublic <$> arbitrary++-- | ED25519 secret cryptographic key.+newtype SecretKey = SecretKey+  { unSecretKey :: Ed25519.SecretKey+  } deriving stock (Show, Eq)++-- | Deterministicaly generate a secret key from seed.+detSecretKey :: ByteString -> SecretKey+detSecretKey seed = SecretKey $ deterministic seed Ed25519.generateSecretKey++instance Arbitrary SecretKey where+  arbitrary = detSecretKey . BS.pack <$> vector 32++-- | Create a public key from a secret key.+toPublic :: SecretKey -> PublicKey+toPublic = PublicKey . Ed25519.toPublic . unSecretKey++-- | ED25519 cryptographic signature.+newtype Signature = Signature+  { unSignature :: Ed25519.Signature+  } deriving stock (Show, Eq)++instance Arbitrary Signature where+  arbitrary = sign <$> arbitrary <*> (encodeUtf8 @String <$> arbitrary)++----------------------------------------------------------------------------+-- Conversion to/from raw bytes (no checksums, tags or anything)+----------------------------------------------------------------------------++-- | Convert a 'PublicKey' to raw bytes.+publicKeyToBytes :: ByteArray ba => PublicKey -> ba+publicKeyToBytes = convert . unPublicKey++-- | Make a 'PublicKey' from raw bytes.+mkPublicKey :: ByteArrayAccess ba => ba -> Either CryptoParseError PublicKey+mkPublicKey =+  onCryptoFailure (Left . CryptoParseCryptoError) (Right . PublicKey) .+  Ed25519.publicKey++publicKeyLengthBytes :: Integral n => n+publicKeyLengthBytes = fromIntegral Ed25519.publicKeySize++-- | Convert a 'Signature' to raw bytes.+signatureToBytes :: ByteArray ba => Signature -> ba+signatureToBytes = convert . unSignature++-- | Make a 'Signature' from raw bytes.+mkSignature :: ByteArrayAccess ba => ba -> Either CryptoParseError Signature+mkSignature =+  onCryptoFailure (Left . CryptoParseCryptoError) (Right . Signature) .+  Ed25519.signature++signatureLengthBytes :: Integral n => n+signatureLengthBytes = fromIntegral Ed25519.signatureSize++----------------------------------------------------------------------------+-- Magic bytes+----------------------------------------------------------------------------++publicKeyTag :: ByteString+publicKeyTag = "\13\15\37\217"++secretKeyTag :: ByteString+secretKeyTag = "\13\15\58\7"++signatureTag :: ByteString+signatureTag = "\9\245\205\134\18"++----------------------------------------------------------------------------+-- Formatting+----------------------------------------------------------------------------++formatPublicKey :: PublicKey -> Text+formatPublicKey = formatImpl publicKeyTag . unPublicKey++mformatPublicKey :: PublicKey -> MText+mformatPublicKey = mkMTextUnsafe . formatPublicKey++instance Buildable PublicKey where+  build = build . formatPublicKey++parsePublicKey :: Text -> Either CryptoParseError PublicKey+parsePublicKey = parseImpl publicKeyTag mkPublicKey++formatSecretKey :: SecretKey -> Text+formatSecretKey = formatImpl secretKeyTag . unSecretKey++instance Buildable SecretKey where+  build = build . formatSecretKey++formatSignature :: Signature -> Text+formatSignature = formatImpl signatureTag . unSignature++mformatSignature :: Signature -> MText+mformatSignature = mkMTextUnsafe . formatSignature++instance Buildable Signature where+  build = build . formatSignature++parseSignature :: Text -> Either CryptoParseError Signature+parseSignature = parseImpl signatureTag mkSignature++----------------------------------------------------------------------------+-- Signing+----------------------------------------------------------------------------++-- | Sign a message using the secret key.+sign :: SecretKey -> ByteString -> Signature+sign sk =+  Signature .+  Ed25519.sign (unSecretKey sk) (unPublicKey (toPublic sk)) . blake2b++-- | Check that a sequence of bytes has been signed with a given key.+checkSignature :: PublicKey -> Signature -> ByteString -> Bool+checkSignature (PublicKey pk) (Signature sig) bytes =+  Ed25519.verify pk (blake2b bytes) sig
+ src/Tezos/Crypto/Hash.hs view
@@ -0,0 +1,35 @@+-- | Cryptographic primitives related to hashing.++module Tezos.Crypto.Hash+  ( blake2b+  , blake2b160+  , sha256+  , sha512+  ) where++import Crypto.Hash (Blake2b_160, Blake2b_256, Digest, SHA256, SHA512, hash)+import qualified Data.ByteArray as ByteArray++-- | Compute a cryptographic hash of a bytestring using the+-- Blake2b_256 cryptographic hash function. It's used by the BLAKE2B+-- instruction in Michelson.+blake2b :: ByteString -> ByteString+blake2b = fromDigest @Blake2b_256 . hash++-- | Compute a cryptographic hash of a bytestring using the+-- Blake2b_160 cryptographic hash function.+blake2b160 :: ByteString -> ByteString+blake2b160 = fromDigest @Blake2b_160 . hash++-- | Compute a cryptographic hash of a bytestring using the+-- Sha256 cryptographic hash function.+sha256 :: ByteString -> ByteString+sha256 = fromDigest @SHA256 . hash++-- | Compute a cryptographic hash of a bytestring using the+-- Sha512 cryptographic hash function.+sha512 :: ByteString -> ByteString+sha512 = fromDigest @SHA512 . hash++fromDigest :: forall a. Digest a -> ByteString+fromDigest = ByteArray.convert
+ src/Tezos/Crypto/P256.hs view
@@ -0,0 +1,173 @@+{-# LANGUAGE DerivingStrategies #-}++-- | P256 cryptographic primitives.+--+-- This module is mostly a stub, it doesn't implement actual crypto.+-- TODO (#18) implement crypto properly.++module Tezos.Crypto.P256+  ( -- * Cryptographic primitive types+    PublicKey (..)+  , SecretKey+  , Signature (..)+  , detSecretKey+  , toPublic++  -- * Raw bytes (no checksums, tags or anything)+  , publicKeyToBytes+  , mkPublicKey+  , publicKeyLengthBytes+  , signatureToBytes+  , mkSignature+  , signatureLengthBytes++  -- * Formatting and parsing+  , formatPublicKey+  , mformatPublicKey+  , parsePublicKey+  , formatSignature+  , mformatSignature+  , parseSignature++  -- * Signing+  , checkSignature+  ) where++import Crypto.Random (getRandomBytes)+import Data.ByteArray (ByteArray, ByteArrayAccess)+import qualified Data.ByteArray as BA+import qualified Data.ByteString as BS+import Fmt (Buildable, build)+import Test.QuickCheck (Arbitrary(..), vector)++import Michelson.Text+import Tezos.Crypto.Util++----------------------------------------------------------------------------+-- Types, instances, conversions+----------------------------------------------------------------------------++-- | P256 public cryptographic key.+newtype PublicKey = PublicKey+  { unPublicKey :: ByteString+  } deriving stock (Show, Eq)++instance Arbitrary PublicKey where+  arbitrary = toPublic <$> arbitrary++-- | P256 secret cryptographic key.+newtype SecretKey = SecretKey+  { unSecretKey :: ByteString+  } deriving stock (Show, Eq)++-- | Deterministicaly generate a secret key from seed.+detSecretKey :: ByteString -> SecretKey+detSecretKey seed =+  SecretKey $ deterministic seed $ getRandomBytes publicKeyLengthBytes++instance Arbitrary SecretKey where+  arbitrary = detSecretKey . BS.pack <$> vector 32++-- | Create a public key from a secret key.+toPublic :: SecretKey -> PublicKey+toPublic = PublicKey . unSecretKey++-- | P256 cryptographic signature.+newtype Signature = Signature+  { unSignature :: ByteString+  } deriving stock (Show, Eq)++instance Arbitrary Signature where+  arbitrary = Signature . BS.pack <$> replicateM signatureLengthBytes arbitrary++----------------------------------------------------------------------------+-- Conversion to/from raw bytes (no checksums, tags or anything)+----------------------------------------------------------------------------++-- | Convert a 'PublicKey' to raw bytes.+--+-- TODO (#18): implement properly.+publicKeyToBytes :: forall ba. ByteArray ba => PublicKey -> ba+publicKeyToBytes = BA.convert . unPublicKey++-- | Make a 'PublicKey' from raw bytes.+--+-- TODO (#18): implement properly.+mkPublicKey :: ByteArrayAccess ba => ba -> Either CryptoParseError PublicKey+mkPublicKey ba+  | l == publicKeyLengthBytes =+    Right $ PublicKey (BA.convert ba)+  | otherwise =+    Left $ CryptoParseUnexpectedLength "public key" l+  where+    l = BA.length ba++publicKeyLengthBytes :: Integral n => n+publicKeyLengthBytes = 33++-- | Convert a 'PublicKey' to raw bytes.+--+-- TODO (#18): implement properly.+signatureToBytes :: ByteArray ba => Signature -> ba+signatureToBytes = BA.convert . unSignature++-- | Make a 'Signature' from raw bytes.+--+-- TODO (#18): implement properly.+mkSignature :: ByteArray ba => ba -> Either CryptoParseError Signature+mkSignature ba+  | l == signatureLengthBytes =+    Right $ Signature (BA.convert ba)+  | otherwise =+    Left $ CryptoParseUnexpectedLength "signature" l+  where+    l = BA.length ba++signatureLengthBytes :: Integral n => n+signatureLengthBytes = 64++----------------------------------------------------------------------------+-- Magic bytes+----------------------------------------------------------------------------++publicKeyTag :: ByteString+publicKeyTag = "\003\178\139\127"++signatureTag :: ByteString+signatureTag = "\054\240\044\052"++----------------------------------------------------------------------------+-- Formatting+----------------------------------------------------------------------------++formatPublicKey :: PublicKey -> Text+formatPublicKey = formatImpl @ByteString publicKeyTag . publicKeyToBytes++mformatPublicKey :: PublicKey -> MText+mformatPublicKey = mkMTextUnsafe . formatPublicKey++instance Buildable PublicKey where+  build = build . formatPublicKey++parsePublicKey :: Text -> Either CryptoParseError PublicKey+parsePublicKey = parseImpl publicKeyTag mkPublicKey++formatSignature :: Signature -> Text+formatSignature = formatImpl @ByteString signatureTag . signatureToBytes++mformatSignature :: Signature -> MText+mformatSignature = mkMTextUnsafe . formatSignature++instance Buildable Signature where+  build = build . formatSignature++parseSignature :: Text -> Either CryptoParseError Signature+parseSignature = parseImpl signatureTag mkSignature++----------------------------------------------------------------------------+-- Signing+----------------------------------------------------------------------------++-- | Check that a sequence of bytes has been signed with a given key.+checkSignature :: PublicKey -> Signature -> ByteString -> Bool+checkSignature _ _ _ = False
+ src/Tezos/Crypto/Secp256k1.hs view
@@ -0,0 +1,233 @@+{-# LANGUAGE DerivingStrategies #-}++-- | Secp256k1 cryptographic primitives.++module Tezos.Crypto.Secp256k1+  ( -- * Cryptographic primitive types+    PublicKey (..)+  , SecretKey+  , Signature (..)+  , detSecretKey+  , toPublic++  -- * Raw bytes (no checksums, tags or anything)+  , publicKeyToBytes+  , mkPublicKey+  , publicKeyLengthBytes+  , signatureToBytes+  , mkSignature+  , signatureLengthBytes++  -- * Formatting and parsing+  , formatPublicKey+  , mformatPublicKey+  , parsePublicKey+  , formatSignature+  , mformatSignature+  , parseSignature++  -- * Signing+  , sign+  , checkSignature+  ) where++import Crypto.Hash (Blake2b_256(..))+import Crypto.Number.Serialize (i2ospOf_, os2ip)+import qualified Crypto.PubKey.ECC.ECDSA as ECDSA+import qualified Crypto.PubKey.ECC.Generate as ECC.Generate+import Crypto.PubKey.ECC.Types (Curve, CurveName(..), Point(..), curveSizeBits, getCurveByName)+import Crypto.Random (MonadRandom, drgNewSeed, seedFromInteger, withDRG)+import Data.ByteArray (ByteArray, ByteArrayAccess)+import qualified Data.ByteArray as BA+import qualified Data.ByteString as BS+import Fmt (Buildable, build)+import Test.QuickCheck (Arbitrary(..), vector)++import Michelson.Text+import Tezos.Crypto.Util++curve :: Curve+curve = getCurveByName SEC_p256k1++curveSizeBytes :: Int+curveSizeBytes = curveSizeBits curve `div` 8++----------------------------------------------------------------------------+-- Types, instances, conversions+----------------------------------------------------------------------------++-- | Secp256k1 public cryptographic key.+data PublicKey = PublicKey+  { unPublicKey :: ECDSA.PublicKey+  , pkBytes :: !(Maybe ByteString)+  -- ^ This is the hack we use to make serialization correct.+  -- Decoding is currently not implemented, so when we have to+  -- decode bytes we remember these bytes and produce some random+  -- public key.+  --+  -- TODO (#18) remove it.+  } deriving stock (Show)++-- TODO (#18): derive it instead once the above hack is removed.+instance Eq PublicKey where+  pk1 == pk2 = publicKeyToBytes @ByteString pk1 == publicKeyToBytes pk2++instance Arbitrary PublicKey where+  arbitrary = toPublic <$> arbitrary++-- | Secp256k1 secret cryptographic key.+newtype SecretKey = SecretKey+  { unSecretKey :: ECDSA.KeyPair+  } deriving stock (Show, Eq)++-- | Deterministicaly generate a secret key from seed.+detSecretKey :: ByteString -> SecretKey+detSecretKey seed = deterministic seed $ detSecretKeyDo++detSecretKeyDo :: MonadRandom m => m SecretKey+detSecretKeyDo = SecretKey <$> do+  (publicKey, privateKey) <- ECC.Generate.generate curve+  return $+    ECDSA.KeyPair curve (ECDSA.public_q publicKey) (ECDSA.private_d privateKey)++instance Arbitrary SecretKey where+  arbitrary = detSecretKey . BS.pack <$> vector 32++-- | Create a public key from a secret key.+toPublic :: SecretKey -> PublicKey+toPublic =+  flip PublicKey Nothing .+  ECDSA.PublicKey curve . (\(ECDSA.KeyPair _ pp _) -> pp) . unSecretKey++-- | Secp256k1 cryptographic signature.+newtype Signature = Signature+  { unSignature :: ECDSA.Signature+  } deriving stock (Show, Eq)++instance Arbitrary Signature where+  arbitrary = do+    seed <- drgNewSeed . seedFromInteger <$> arbitrary+    byteToSign <- arbitrary+    return $ fst $ withDRG seed $ do+      sk <- detSecretKeyDo+      sign sk (one byteToSign)++----------------------------------------------------------------------------+-- Conversion to/from raw bytes (no checksums, tags or anything)+----------------------------------------------------------------------------++-- | Convert a 'PublicKey' to raw bytes.+--+-- TODO (#18): apparently it uses compressed SEC format as described in+-- <https://www.oreilly.com/library/view/programming-bitcoin/9781492031482/ch04.html>+-- However, it is not tested yet.+publicKeyToBytes :: forall ba. ByteArray ba => PublicKey -> ba+publicKeyToBytes (PublicKey _ (Just bytes)) = BA.convert bytes+publicKeyToBytes (PublicKey (ECDSA.PublicKey _ publicPoint) Nothing) =+  case publicPoint of+    Point x y -> prefix y `BA.append` coordToBytes x+    PointO -> error "PublicKey somehow contains infinity point"+  where+    prefix :: Integer -> ba+    prefix y+      | odd y = BA.singleton 0x03+      | otherwise = BA.singleton 0x02++-- | Make a 'PublicKey' from raw bytes.+--+-- TODO (#18): it should decode from compressed SEC format, but it's left+-- for a future task, so for now we return a constant.+mkPublicKey :: ByteArrayAccess ba => ba -> Either CryptoParseError PublicKey+mkPublicKey ba+  | l == publicKeyLengthBytes =+    Right $ PublicKey (ECDSA.PublicKey curve $ Point 11 12) (Just $ BA.convert ba)+  | otherwise =+    Left $ CryptoParseUnexpectedLength "public key" l+  where+    l = BA.length ba++publicKeyLengthBytes :: Integral n => n+publicKeyLengthBytes = fromIntegral $ 1 + curveSizeBytes++-- | Convert a 'PublicKey' to raw bytes.+--+-- TODO (#18): apparently a signature always has 64 bytes, so this+-- format might be correct, but it is not tested.+signatureToBytes :: ByteArray ba => Signature -> ba+signatureToBytes (Signature (ECDSA.Signature r s)) =+  coordToBytes r <> coordToBytes s++-- | Make a 'Signature' from raw bytes.+--+-- TODO (#18): apparently a signature always has 64 bytes, so this+-- format might be correct, but it is not tested.+mkSignature :: ByteArray ba => ba -> Either CryptoParseError Signature+mkSignature ba+  | l == signatureLengthBytes+  , (rBytes, sBytes) <- BA.splitAt curveSizeBytes ba =+    Right $ Signature (ECDSA.Signature (os2ip rBytes) (os2ip sBytes))+  | otherwise =+    Left $ CryptoParseUnexpectedLength "signature" l+  where+    l = BA.length ba++signatureLengthBytes :: Integral n => n+signatureLengthBytes = fromIntegral $ curveSizeBytes + curveSizeBytes++-- TODO (#18): maybe this function doesn't make sense.+-- We are using `i2ospOf_` because `curveSizeBits` ensures that+-- the number won't have more than that many bytes.+coordToBytes :: ByteArray ba => Integer -> ba+coordToBytes = i2ospOf_ curveSizeBytes++----------------------------------------------------------------------------+-- Magic bytes+----------------------------------------------------------------------------++publicKeyTag :: ByteString+publicKeyTag = "\003\254\226\086"++signatureTag :: ByteString+signatureTag = "\013\115\101\019\063"++----------------------------------------------------------------------------+-- Formatting+----------------------------------------------------------------------------++formatPublicKey :: PublicKey -> Text+formatPublicKey = formatImpl @ByteString publicKeyTag . publicKeyToBytes++mformatPublicKey :: PublicKey -> MText+mformatPublicKey = mkMTextUnsafe . formatPublicKey++instance Buildable PublicKey where+  build = build . formatPublicKey++parsePublicKey :: Text -> Either CryptoParseError PublicKey+parsePublicKey = parseImpl publicKeyTag mkPublicKey++formatSignature :: Signature -> Text+formatSignature = formatImpl @ByteString signatureTag . signatureToBytes++mformatSignature :: Signature -> MText+mformatSignature = mkMTextUnsafe . formatSignature++instance Buildable Signature where+  build = build . formatSignature++parseSignature :: Text -> Either CryptoParseError Signature+parseSignature = parseImpl signatureTag mkSignature++----------------------------------------------------------------------------+-- Signing+----------------------------------------------------------------------------++-- | Sign a message using the secret key.+sign :: MonadRandom m => SecretKey -> ByteString -> m Signature+sign (SecretKey keyPair) =+  fmap Signature . ECDSA.sign (ECDSA.toPrivateKey keyPair) Blake2b_256++-- | Check that a sequence of bytes has been signed with a given key.+checkSignature :: PublicKey -> Signature -> ByteString -> Bool+checkSignature (PublicKey pk _) (Signature sig) =+  ECDSA.verify Blake2b_256 pk sig
+ src/Tezos/Crypto/Util.hs view
@@ -0,0 +1,113 @@+-- | Utilities shared by multiple cryptographic primitives.++module Tezos.Crypto.Util+  ( CryptoParseError (..)+  , encodeBase58Check+  , decodeBase58Check+  , B58CheckWithPrefixError (..)+  , decodeBase58CheckWithPrefix+  , formatImpl+  , parseImpl+  , firstRight+  , deterministic+  ) where++import Crypto.Error (CryptoError)+import Crypto.Number.Serialize (os2ip)+import Crypto.Random (ChaChaDRG, MonadPseudoRandom, drgNewSeed, seedFromInteger, withDRG)+import qualified Data.ByteArray as ByteArray+import qualified Data.ByteString as BS+import qualified Data.ByteString.Base58 as Base58+import Fmt (Buildable, Builder, build, fmt, hexF)++import Tezos.Crypto.Hash++-- | Error that can happen during parsing of cryptographic primitive types.+data CryptoParseError+  = CryptoParseWrongBase58Check+  | CryptoParseWrongTag !ByteString+  | CryptoParseCryptoError !CryptoError+  | CryptoParseUnexpectedLength !Builder !Int+  deriving (Show, Eq)++instance Buildable CryptoParseError where+  build =+    \case+      CryptoParseWrongBase58Check -> "Wrong base58check encoding of bytes"+      CryptoParseWrongTag tag -> "Prefix is wrong tag: " <> fmt (hexF tag)+      CryptoParseCryptoError err ->+        "Cryptographic library reported an error: " <>+        build (displayException err)+      CryptoParseUnexpectedLength what l ->+        "Unexpected length of " <> what <> ": " <> build l++-- | Encode a bytestring in Base58Check format.+encodeBase58Check :: ByteString -> Text+encodeBase58Check =+  decodeUtf8 . Base58.encodeBase58 Base58.bitcoinAlphabet . withCheckSum+  where+    withCheckSum :: ByteString -> ByteString+    withCheckSum bs = bs <> checkSum bs++-- | Decode a bytestring from Base58Check format.+decodeBase58Check :: Text -> Maybe ByteString+decodeBase58Check text = do+  bytes <- Base58.decodeBase58 Base58.bitcoinAlphabet (encodeUtf8 text)+  let (payload, chk) = BS.splitAt (length bytes - 4) bytes+  guard $ chk == checkSum payload+  return payload++checkSum :: ByteString -> ByteString+checkSum = BS.take 4 . (sha256 . sha256)++data B58CheckWithPrefixError+  = B58CheckWithPrefixWrongPrefix ByteString+  | B58CheckWithPrefixWrongEncoding+  deriving (Show)++-- | Parse a base58check encoded value expecting some prefix. If the+-- actual prefix matches the expected one, it's stripped of and the+-- resulting payload is returned.+decodeBase58CheckWithPrefix ::+  ByteString -> Text -> Either B58CheckWithPrefixError ByteString+decodeBase58CheckWithPrefix prefix text =+  case decodeBase58Check text of+    Nothing -> Left B58CheckWithPrefixWrongEncoding+    Just bs ->+      let (actualPrefix, payload) = BS.splitAt (length prefix) bs+       in if actualPrefix == prefix+          then Right payload+          else Left (B58CheckWithPrefixWrongPrefix actualPrefix)++-- | Template for 'format*' functions.+formatImpl :: ByteArray.ByteArrayAccess x => ByteString -> x -> Text+formatImpl tag = encodeBase58Check . mappend tag . ByteArray.convert++-- | Template for 'parse*' functions.+parseImpl+  :: ByteString+  -> (ByteString -> Either CryptoParseError res)+  -> Text+  -> Either CryptoParseError res+parseImpl expectedTag constructor text = do+  let convertErr :: B58CheckWithPrefixError -> CryptoParseError+      convertErr =+        \case B58CheckWithPrefixWrongPrefix prefix -> CryptoParseWrongTag prefix+              B58CheckWithPrefixWrongEncoding -> CryptoParseWrongBase58Check+  payload <- first convertErr $ decodeBase58CheckWithPrefix expectedTag text+  constructor payload++-- | Returns first encountered 'Right' in a list. If there are none,+-- returns arbitrary 'Left'.+-- It is useful to implement parsing.+firstRight :: NonEmpty (Either e a) -> Either e a+firstRight (h :| rest) =+  case h of+    Left e -> maybe (Left e) firstRight $ nonEmpty rest+    Right a -> Right a++-- | Do randomized action using specified seed.+deterministic :: ByteString -> MonadPseudoRandom ChaChaDRG a -> a+deterministic seed = fst . withDRG chachaSeed+  where+    chachaSeed = drgNewSeed . seedFromInteger . os2ip $ seed
src/Util/Generic.hs view
@@ -2,10 +2,15 @@ module Util.Generic   ( mkGenericTree   , mkGenericTreeVec++  , GenericTypeName   ) where  import Control.Exception (assert)+import qualified Data.Kind as Kind import qualified Data.Vector as V+import qualified GHC.Generics as G+import GHC.TypeLits (Symbol)  -- | Rebuild a list into a binary tree of exactly the same form which -- 'Data.Generic' uses to represent datatypes.@@ -13,10 +18,12 @@ -- Along with the original list you have to provide constructor for intermediate -- nodes - it accepts zero-based index of the leftmost element of the right tree -- and merged trees themselves.-mkGenericTree :: (Int -> a -> a -> a) -> NonEmpty a -> a+mkGenericTree :: (Natural -> a -> a -> a) -> NonEmpty a -> a mkGenericTree mkNode = mkGenericTreeVec id mkNode . V.fromList . toList -mkGenericTreeVec :: HasCallStack => (a -> b) -> (Int -> b -> b -> b) -> V.Vector a -> b+mkGenericTreeVec+  :: HasCallStack+  => (a -> b) -> (Natural -> b -> b -> b) -> V.Vector a -> b mkGenericTreeVec mkLeaf mkNode vector   | V.null vector = error "Empty vector"   | otherwise = mkTreeDo 0 vector@@ -27,4 +34,12 @@           let mid = V.length es `div` 2               mid' = idxBase + mid               (h, t) = V.splitAt mid es-          in mkNode mid' (mkTreeDo idxBase h) (mkTreeDo mid' t)+          in mkNode (fromIntegral mid') (mkTreeDo idxBase h) (mkTreeDo mid' t)++-- | Extract datatype name via its Generic representation.+--+-- For polymorphic types this throws away all type arguments.+type GenericTypeName a = GTypeName (G.Rep a)++type family GTypeName (x :: Kind.Type -> Kind.Type) :: Symbol where+  GTypeName (G.D1 ('G.MetaData tyName _ _ _) _) = tyName
src/Util/IO.hs view
@@ -1,6 +1,7 @@ module Util.IO   ( readFileUtf8   , writeFileUtf8+  , appendFileUtf8   , withEncoding   , hSetTranslit   ) where@@ -16,6 +17,10 @@ writeFileUtf8 :: Print text => FilePath -> text -> IO () writeFileUtf8 name txt =   withFile name WriteMode $ \h -> hSetEncoding h utf8 >> hPutStr h txt++appendFileUtf8 :: Print text => FilePath -> text -> IO ()+appendFileUtf8 name txt =+  withFile name AppendMode $ \h -> hSetEncoding h utf8 >> hPutStr h txt  withEncoding :: Handle -> TextEncoding -> IO () -> IO () withEncoding handle encoding action = do
src/Util/Instances.hs view
@@ -4,6 +4,7 @@ module Util.Instances () where  import Data.Default (Default(..))+import Data.Functor.Identity (Identity(..)) import Fmt (Buildable(..))  instance Default Natural where@@ -11,3 +12,6 @@  instance Buildable Natural where   build = build @Integer . fromIntegral++instance Buildable a => (Buildable (Identity a)) where+  build (Identity x) = build x
src/Util/Lens.hs view
@@ -1,9 +1,16 @@+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+ module Util.Lens   ( postfixLFields+  , makeLensesWith+  , unwrappedP   ) where -import Control.Lens (LensRules, lensField, lensRules, mappingNamer)+import Control.Lens (LensRules, Wrapped(..), lensField, lensRules, makeLensesWith, mappingNamer)  -- | For datatype with "myNyan" field it will create "myNyanL" lens. postfixLFields :: LensRules postfixLFields = lensRules & lensField .~ mappingNamer (\s -> [s++"L"])++unwrappedP :: Wrapped a => Proxy a -> Proxy (Unwrapped a)+unwrappedP _ = Proxy
+ src/Util/Markdown.hs view
@@ -0,0 +1,114 @@+-- | A small Markdown eDSL.+module Util.Markdown+  ( Markdown+  , HeaderLevel (..)+  , nextHeaderLevel+  , mdHeader+  , mdSubsection+  , mdSubsectionTitle+  , mdBold+  , mdItalic+  , mdTicked+  , mdRef+  , mdLocalRef+  , mdAnchor+  , mdSeparator+  , mdSpoiler+  , mdComment+  , md+  ) where++import qualified Data.String.Interpolate.IsString as Interpolate+import Data.String.Interpolate.Util (unindent)+import Fmt (Builder, build, (+|), (|+))+import Language.Haskell.TH.Quote (QuasiQuoter(..))++-- | A piece of markdown document.+--+-- This is opposed to 'Text' type, which in turn is not supposed to contain+-- markup elements.+type Markdown = Builder++-- | Level of header, starting from 1.+newtype HeaderLevel = HeaderLevel Int++nextHeaderLevel :: HeaderLevel -> HeaderLevel+nextHeaderLevel (HeaderLevel l) = HeaderLevel (l + 1)++mdHeader :: HeaderLevel -> Markdown -> Markdown+mdHeader (HeaderLevel lvl) text =+  mconcat (replicate lvl "#") +| " " +| text |+ "\n\n"++mdSubsectionTitle :: Markdown -> Markdown+mdSubsectionTitle title = mdBold (title <> ":")++mdSubsection :: Markdown -> Markdown -> Markdown+mdSubsection name txt = mdSubsectionTitle name <> " " <> txt++mdBold :: Markdown -> Markdown+mdBold x = "**" <> x <> "**"++mdItalic :: Markdown -> Markdown+mdItalic x = "*" <> x <> "*"++mdTicked :: Markdown -> Markdown+mdTicked x = "`" +| x |+ "`"++mdEscapeAnchorS :: String -> Markdown+mdEscapeAnchorS = \case+  [] -> ""+  ' ' : s -> "-" <> mdEscapeAnchorS s+  '(' : s -> "lparen" <> mdEscapeAnchorS s+  ')' : s -> "rparen" <> mdEscapeAnchorS s+  '[' : s -> "lbracket" <> mdEscapeAnchorS s+  ']' : s -> "rbracket" <> mdEscapeAnchorS s+  '{' : s -> "lbrace" <> mdEscapeAnchorS s+  '}' : s -> "rbrace" <> mdEscapeAnchorS s+  ',' : s -> "comma" <> mdEscapeAnchorS s+  ';' : s -> "semicolon" <> mdEscapeAnchorS s+  ':' : s -> "colon" <> mdEscapeAnchorS s+  '#' : s -> "hash" <> mdEscapeAnchorS s+  c : s -> build (toText [c]) <> mdEscapeAnchorS s++-- | Turn text into valid anchor. Human-readability is not preserved.+mdEscapeAnchor :: Text -> Markdown+mdEscapeAnchor = mdEscapeAnchorS . toString++mdRef :: Markdown -> Markdown -> Markdown+mdRef txt ref = "[" <> txt <> "](" <> ref <> ")"++mdLocalRef :: Markdown -> Text -> Markdown+mdLocalRef txt anchor = mdRef txt ("#" <> mdEscapeAnchor anchor)++mdAnchor :: Text -> Markdown+mdAnchor name = "<a name=\"" <> mdEscapeAnchor name <> "\"></a>\n\n"++mdSeparator :: Markdown+mdSeparator = "---\n\n"++-- | Text which is hidden until clicked.+mdSpoiler :: Markdown -> Markdown -> Markdown+mdSpoiler name contents =+  mconcat $ intersperse "\n"+    [ "<details>"+    , "  <summary>" <> htmlBold (build name) <> "</summary>"+    , contents+    , "</details>"+    , "<p>"+    ]+  where+    -- Markdown's bold does not always work within spoiler header+    htmlBold txt = "<b>" <> txt <> "</b>"++mdComment :: Builder -> Builder+mdComment commentText =+  "<!---\n" +| commentText |+ "\n-->"++-- | Quasi quoter for Markdown.+md :: QuasiQuoter+md = QuasiQuoter+  { quoteExp = \s -> [|fromString @Markdown $ unindent $(quoteExp Interpolate.i s) |]+  , quotePat = \_ -> fail "Cannot be used at pattern position"+  , quoteType = \_ -> fail "Cannot be used at type position"+  , quoteDec = \_ -> fail "Cannot be used as declaration"+  }
src/Util/Named.hs view
@@ -1,17 +1,25 @@+{-# LANGUAGE DeriveDataTypeable #-} {-# OPTIONS_GHC -Wno-orphans #-}  -- | Additional functionality for 'named' package. module Util.Named-  ( (.!)+  ( (:!)+  , (:?)+  , (.!)   , (.?)   , (<.!>)   , (<.?>)+  , ApplyNamedFunctor   , NamedInner   ) where  import Control.Lens (Wrapped(..), iso)+import Data.Aeson (FromJSON, ToJSON)+import Data.Data (Data)+import qualified Data.Kind as Kind+import Fmt (Buildable(..)) import GHC.TypeLits (KnownSymbol, symbolVal)-import Named (Name, NamedF(..))+import Named ((:!), (:?), Name, NamedF(..)) import qualified Text.Show  (.!) :: Name name -> a -> NamedF Identity a name@@ -26,10 +34,17 @@ (<.?>) :: Functor m => Name name -> m (Maybe a) -> m (NamedF Maybe a name) (<.?>) name = fmap (name .?) -type family NamedInner n where-  NamedInner (NamedF Identity a _) = a-  NamedInner (NamedF Maybe a _) = Maybe a+type family ApplyNamedFunctor (f :: Kind.Type -> Kind.Type) (a :: Kind.Type) where+  ApplyNamedFunctor Identity a = a+  ApplyNamedFunctor Maybe a = Maybe a +type family NamedInner (n :: Kind.Type) where+  NamedInner (NamedF f a _) = ApplyNamedFunctor f a++----------------------------------------------------------------------------+-- Instances+----------------------------------------------------------------------------+ instance Wrapped (NamedF Identity a name) where   type Unwrapped (NamedF Identity a name) = a   _Wrapped' = iso (\(ArgF a) -> runIdentity a) (ArgF . Identity)@@ -38,7 +53,20 @@   type Unwrapped (NamedF Maybe a name) = Maybe a   _Wrapped' = iso (\(ArgF a) -> a) ArgF -deriving instance Eq a => Eq (NamedF Identity a name)+deriving instance Eq (f a) => Eq (NamedF f a name)+deriving instance Ord (f a) => Ord (NamedF f a name)  instance (Show a, KnownSymbol name) => Show (NamedF Identity a name) where   show (ArgF a) = symbolVal (Proxy @name) <> " :! " <> show a++instance (KnownSymbol name, Buildable (f a)) => Buildable (NamedF f a name) where+  build (ArgF a) = build (symbolVal (Proxy @name)) <> ": " <> build a++deriving instance+  (Typeable f, Typeable a, KnownSymbol name, Data (f a)) =>+  Data (NamedF f a name)++deriving instance ToJSON a => ToJSON (NamedF Identity a name)+deriving instance ToJSON a => ToJSON (NamedF Maybe a name)+deriving instance FromJSON a => FromJSON (NamedF Identity a name)+deriving instance FromJSON a => FromJSON (NamedF Maybe a name)
src/Util/Peano.hs view
@@ -1,4 +1,5 @@ {-# OPTIONS_GHC -Wno-orphans #-}+{-# LANGUAGE UndecidableSuperClasses #-} {-# OPTIONS_GHC -Wno-redundant-constraints #-}  -- | Type-nat utilities.@@ -14,30 +15,38 @@ module Util.Peano   ( -- * General     Peano+    -- @gromak: I think we should not export Nat, but we want to+    -- export `Z` and `S` and I do not know how to do it without+    -- exporting `Nat`.+  , Nat (Z, S)   , ToPeano-  , Length+  , FromPeano   , KnownPeano (..)-  , peanoVal'   , Sing (SZ, SS)+  , peanoVal'+  , peanoValSing++  -- * Lists+  , Length   , At+  , Drop+  , Take      -- * Morley-specific utils   , IsLongerThan   , LongerThan   , RequireLongerThan-  , requiredLongerThan+  , IsLongerOrSameLength+  , LongerOrSameLength+  , RequireLongerOrSameLength   ) where -import Prelude hiding (Nat)- import Data.Singletons (Sing, SingI(..))-import qualified GHC.TypeNats as GHC (Nat)-import Unsafe.Coerce (unsafeCoerce)-import Data.Constraint (Dict (..))-import GHC.TypeLits (TypeError, ErrorMessage (..)) import Data.Type.Bool (If) import Data.Vinyl.TypeLevel (Nat(..), RLength)-import GHC.TypeNats (type (-), type (+))+import GHC.TypeLits (ErrorMessage(..), TypeError)+import GHC.TypeNats (type (+), type (-))+import qualified GHC.TypeNats as GHC (Nat)  ---------------------------------------------------------------------------- -- General@@ -49,18 +58,15 @@ -- normal 'Nat's in user API, need to distinguish them somehow. type Peano = Nat -type family ToPeano (n :: GHC.Nat) :: Nat where+type family ToPeano (n :: GHC.Nat) :: Peano where   ToPeano 0 = 'Z   ToPeano a = 'S (ToPeano (a - 1)) -type family FromPeano (n :: Nat) :: GHC.Nat where+type family FromPeano (n :: Peano) :: GHC.Nat where   FromPeano 'Z = 0   FromPeano ('S a) = 1 + FromPeano a -type family Length l where-  Length l = RLength l--class KnownPeano (n :: Nat) where+class KnownPeano (n :: Peano) where   peanoVal :: proxy n -> Natural  instance KnownPeano 'Z where@@ -71,17 +77,29 @@ peanoVal' :: forall n. KnownPeano n => Natural peanoVal' = peanoVal (Proxy @n) +-- | Get runtime value from singleton.+peanoValSing :: forall n. KnownPeano n => Sing n -> Natural+peanoValSing _ = peanoVal' @n+ data instance Sing (_ :: Nat) where   SZ :: Sing 'Z-  SS :: Sing n -> Sing ('S n)+  SS :: (SingI n, KnownPeano n) => Sing n -> Sing ('S n) +deriving instance Show (Sing (n :: Nat)) deriving instance Eq (Sing (n :: Nat))  instance SingI 'Z where   sing = SZ-instance SingI n => SingI ('S n) where+instance (SingI n, KnownPeano n) => SingI ('S n) where   sing = SS (sing @n) +----------------------------------------------------------------------------+-- Lists+----------------------------------------------------------------------------++type family Length l :: Peano where+  Length l = RLength l+ type family At (n :: Peano) s where   At 'Z (x ': _) = x   At ('S n) (_ ': xs) = At n xs@@ -90,17 +108,37 @@       ('Text "You try to access to non-existing element of the stack, n = " ':<>:          'ShowType (FromPeano a)) +type family Drop (n :: Peano) (s :: [k]) :: [k] where+  Drop  'Z s = s+  Drop ('S _) '[] = '[]+  Drop ('S n) (_ ': s) = Drop n s++type family Take (n :: Peano) (s :: [k]) :: [k] where+  Take  'Z _ = '[]+  Take _ '[] = '[]+  Take ('S n) (a ': s) = a ': Take n s+ ---------------------------------------------------------------------------- -- Morley-specific utils ---------------------------------------------------------------------------- +-- Note that we could define type families to return 'Constraint' instead+-- of defining standalone constraint in form `c ~ 'True`, but apparently+-- such constraint would be weaker, e. g. there is an example when with+-- current approach there is no warning, but if we change the approach+-- to return 'Constraint' from type family then GHC complains about+-- non-exhaustive patterns (@gromak).+-- Also we use these `Bool` type families in more than one place, we generate+-- two constraints: one gives more information to GHC and another one produces+-- better error messages on failure.+ -- | Comparison of type-level naturals, as a function. -- -- It is as lazy on the list argument as possible - there is no -- need to know the whole list if the natural argument is small enough. -- This property is important if we want to be able to extract reusable -- parts of code which are aware only of relevant part of stack.-type family IsLongerThan (l :: [k]) (a :: Nat) :: Bool where+type family IsLongerThan (l :: [k]) (a :: Peano) :: Bool where   IsLongerThan (_ ': _) 'Z = 'True   IsLongerThan (_ ': xs) ('S a) = IsLongerThan xs a   IsLongerThan '[] _ = 'False@@ -108,6 +146,17 @@ -- | Comparison of type-level naturals, as a constraint. type LongerThan l a = IsLongerThan l a ~ 'True +-- | Similar to 'IsLongerThan', but returns 'True' when list length+-- equals to the passed number.+type family IsLongerOrSameLength (l :: [k]) (a :: Peano) :: Bool where+  IsLongerOrSameLength _ 'Z = 'True+  IsLongerOrSameLength (_ ': xs) ('S a) = IsLongerOrSameLength xs a+  IsLongerOrSameLength '[] ('S _) = 'False++-- | 'IsLongerOrSameLength' in form of constraint that gives most+-- information to GHC.+type LongerOrSameLength l a = IsLongerOrSameLength l a ~ 'True+ {- | Evaluates list length.  This type family is a best-effort attempt to display neat error messages@@ -128,9 +177,10 @@ -- | Comparison of type-level naturals, raises human-readable compile error -- when does not hold. ----- This is for in eDSL use only, GHC cannot reason about such constraint.-type family RequireLongerThan (l :: [k]) (a :: Nat) :: Constraint where-  RequireLongerThan l a =+-- Here we use the same approach as for 'RequireLongerOrSameLength', this+-- type family is internal.+type family RequireLongerThan' (l :: [k]) (a :: Nat) :: Constraint where+  RequireLongerThan' l a =     If (IsLongerThan l a)        (() :: Constraint)        (TypeError@@ -141,12 +191,34 @@            'Text ":" ':$$: 'ShowType l            )) --- | Derive 'LongerThan' from 'RequireLongerThan'.-requiredLongerThan-  :: forall l a r. (RequireLongerThan l a)-  => (LongerThan l a => r) -> r-requiredLongerThan r = do-  -- It's not clear now to proof GHC this implication so we use-  -- @unsafeCoerce@ below and also disable "-Wredundant-constraints" extension.-  case unsafeCoerce @(Dict (LongerThan '[Int] 'Z)) @(Dict (LongerThan l a)) Dict of-    Dict -> r+class (RequireLongerThan' l a, LongerThan l a) =>+  RequireLongerThan (l :: [k]) (a :: Peano)+instance RequireLongerThan' l a => LongerThan l a =>+  RequireLongerThan l a++-- | 'IsLongerOrSameLength' in form of constraint that produces+-- good error message. Should be used together with 'LongerThan'+-- because 'LongerThan' gives GHC more information.+-- We use it in combination, so that it gives enough information to+-- GHC and also producess good error messages.+type family RequireLongerOrSameLength' (l :: [k]) (a :: Peano) :: Constraint where+  RequireLongerOrSameLength' l a =+    If (IsLongerOrSameLength l a)+       (() :: Constraint)+       (TypeError+          ('Text "Expected stack with length >= " ':<>: 'ShowType (FromPeano a) ':$$:+           'Text "Current stack has size of only " ':<>:+           'ShowType (LengthWithTail l) ':<>:+           'Text ":" ':$$: 'ShowType l+           ))++-- | We can have+-- `RequireLongerOrSameLength = (RequireLongerOrSameLength' l a, LongerOrSameLength l a)`,+-- but apparently the printed error message can be caused by `LongerOrSameLength`+-- rather than `RequireLongerOrSameLength'`.+-- We do not know for sure how it all works, but we think that if we require constraint X before+-- Y (using multiple `=>`s) then X will always be evaluated first.+class (RequireLongerOrSameLength' l a, LongerOrSameLength l a) =>+  RequireLongerOrSameLength (l :: [k]) (a :: Peano)+instance RequireLongerOrSameLength' l a => LongerOrSameLength l a =>+  RequireLongerOrSameLength l a
+ src/Util/Positive.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE DeriveDataTypeable, DerivingStrategies #-}++-- | Definition of 'Positive' type and related utilities.+module Util.Positive+  ( Positive (..)+  , mkPositive+  , lengthNE+  , replicateNE+  ) where++import Data.Aeson (FromJSON, ToJSON)+import Data.Data (Data)+import Fmt (Buildable, pretty)++import Util.Instances ()++-- | Integer values starting from 1.+--+-- We define our own datatype in order to have 'Data' instance for it,+-- which can not be derived for third-party types without exported constructor.+newtype Positive = PositiveUnsafe { unPositive :: Natural }+  deriving stock (Eq, Ord, Data)+  deriving newtype (Show, Buildable, ToJSON, FromJSON)++mkPositive :: (Integral i, Buildable i) => i -> Either Text Positive+mkPositive a+  | a > 0     = Right $ PositiveUnsafe (fromIntegral a)+  | otherwise = Left $ "Number is not positive: " <> pretty a++-- | Count length of non-empty list.+lengthNE :: NonEmpty a -> Positive+lengthNE = PositiveUnsafe . fromIntegral . length++-- | Produce a non empty list consisting of the given value.+replicateNE :: Positive -> a -> NonEmpty a+replicateNE (PositiveUnsafe i) a = a :| replicate (fromIntegral i - 1) a
src/Util/Test/Arbitrary.hs view
@@ -16,6 +16,7 @@ import Test.QuickCheck.Instances.Text () import Test.QuickCheck.Random (mkQCGen) +import Lorentz.UStore import Michelson.ErrorPos (InstrCallStack(..), LetName(..), Pos(..), SrcPos(..)) import Michelson.Test () import Michelson.Untyped@@ -99,8 +100,8 @@       , DUP <$> arbitrary       , pure SWAP       , PUSH <$> arbitrary <*> arbitrary <*> arbitrary-      , SOME <$> arbitrary <*> arbitrary <*> arbitrary-      , NONE <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary+      , SOME <$> arbitrary <*> arbitrary+      , NONE <$> arbitrary <*> arbitrary <*> arbitrary       , UNIT <$> arbitrary <*> arbitrary       , IF_NONE <$> smallList <*> smallList       , PAIR <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary@@ -115,11 +116,12 @@       , SIZE <$> arbitrary       , EMPTY_SET <$> arbitrary <*> arbitrary <*> arbitrary       , EMPTY_MAP <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary+      , EMPTY_BIG_MAP <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary       , MAP <$> arbitrary <*> smallList       , ITER <$> smallList       , MEM <$> arbitrary       , GET <$> arbitrary-      , pure UPDATE+      , UPDATE <$> arbitrary       , IF <$> smallList <*> smallList       , LOOP <$> smallList       , LOOP_LEFT <$> smallList@@ -139,7 +141,7 @@       , MUL <$> arbitrary       , EDIV <$> arbitrary       , ABS <$> arbitrary-      , pure NEG+      , NEG <$> arbitrary       , LSL <$> arbitrary       , LSR <$> arbitrary       , OR <$> arbitrary@@ -155,10 +157,9 @@       , GE <$> arbitrary       , INT <$> arbitrary       , SELF <$> arbitrary-      , CONTRACT <$> arbitrary <*> arbitrary+      , CONTRACT <$> arbitrary <*> arbitrary <*> arbitrary       , TRANSFER_TOKENS <$> arbitrary       , SET_DELEGATE <$> arbitrary-      , CREATE_ACCOUNT <$> arbitrary <*> arbitrary       , CREATE_CONTRACT <$> arbitrary <*> arbitrary <*> arbitrary       , IMPLICIT_ACCOUNT <$> arbitrary       , NOW <$> arbitrary@@ -217,7 +218,7 @@       , pure TKey       , pure TUnit       , pure TSignature-      , TOption <$> arbitrary <*> arbitrary+      , TOption <$> arbitrary       , TList <$> arbitrary       , TSet <$> arbitrary       , pure TOperation@@ -238,11 +239,18 @@  instance ToADTArbitrary CT instance Arbitrary CT where-  arbitrary =  elements [minBound .. maxBound]+  arbitrary = elements [minBound .. maxBound]  instance ToADTArbitrary Comparable instance Arbitrary Comparable where   arbitrary = Comparable <$> arbitrary <*> arbitrary++instance (Ord k, Arbitrary k, Arbitrary v) =>+         Arbitrary (k |~> v) where+  arbitrary = UStoreSubMap <$> arbitrary++instance Arbitrary v => Arbitrary (UStoreFieldExt m v) where+  arbitrary = UStoreField <$> arbitrary  -- | Run given generator deterministically. runGen :: Int -> Gen a -> a
+ src/Util/Text.hs view
@@ -0,0 +1,14 @@+module Util.Text+  ( headToLower+  ) where++import Data.Char (toLower)+import qualified Data.Text as T++-- | Leads first character of text to lower case.+--+-- For empty text this will throw an error.+headToLower :: HasCallStack => Text -> Text+headToLower txt = case T.uncons txt of+  Nothing -> error "Empty text"+  Just (c, cs) -> T.cons (toLower c) cs
src/Util/Type.hs view
@@ -1,9 +1,119 @@+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+ -- | General type utilities. module Util.Type-  ( IsElem+  ( type (==)+  , If+  , type (++)+  , IsElem+  , type (/)+  , type (//)+  , Guard+  , AllUnique+  , RequireAllUnique+  , ReifyList (..)+  , PatternMatch+  , PatternMatchL+  , KnownList (..)+  , KList (..)+  , RSplit+  , rsplit++  , reifyTypeEquality   ) where +import Data.Vinyl.Core (Rec (..))+import Data.Vinyl.TypeLevel (type (++))+import qualified Data.Kind as Kind+import Data.Type.Bool (Not, type (&&), If)+import Unsafe.Coerce (unsafeCoerce)+import Data.Constraint (Dict (..))+import Data.Type.Equality (type (==))+import GHC.TypeLits (Symbol, TypeError, ErrorMessage (..))+ type family IsElem (a :: k) (l :: [k]) :: Bool where   IsElem _ '[] = 'False   IsElem a (a ': _) = 'True   IsElem a (_ ': as) = IsElem a as++-- | Remove all occurences of the given element.+type family (l :: [k]) / (a :: k) where+  '[] / _ = '[]+  (a ': xs) / a = xs / a+  (b ': xs) / a = b ': (xs / a)++-- | Difference between two lists.+type family (l1 :: [k]) // (l2 :: [k]) :: [k] where+  l // '[] = l+  l // (x ': xs) = (l / x) // xs++type family Guard (cond :: Bool) (a :: k) :: Maybe k where+  Guard 'False _ = 'Nothing+  Guard 'True a = 'Just a++type family AllUnique (l :: [k]) :: Bool where+  AllUnique '[] = 'True+  AllUnique (x : xs) = Not (IsElem x xs) && AllUnique xs++type family RequireAllUnique (desc :: Symbol) (l :: [k]) :: Constraint where+  RequireAllUnique _ '[] = ()+  RequireAllUnique desc (x : xs) =+    If (IsElem x xs)+       (TypeError ('Text "Duplicated " ':<>: 'Text desc ':<>: 'Text ":" ':$$:+                   'ShowType x)+       )+       (RequireAllUnique desc xs)++-- | Make sure given type is evaluated.+-- This type family fits only for types of 'Kind.Type' kind.+type family PatternMatch (a :: Kind.Type) :: Constraint where+  PatternMatch Int = ((), ())+  PatternMatch _ = ()++type family PatternMatchL (l :: [k]) :: Constraint where+  PatternMatchL '[] = ((), ())+  PatternMatchL _ = ()++-- | Bring type-level list at term-level using given function+-- to demote its individual elements.+class ReifyList (c :: k -> Constraint) (l :: [k]) where+  reifyList :: (forall a. c a => Proxy a -> r) -> [r]++instance ReifyList c '[] where+  reifyList _ = []++instance (c x, ReifyList c xs) => ReifyList c (x ': xs) where+  reifyList reifyElem = reifyElem (Proxy @x) : reifyList @_ @c @xs reifyElem++-- | Reify type equality from boolean equality.+reifyTypeEquality :: forall a b x. (a == b) ~ 'True => (a ~ b => x) -> x+reifyTypeEquality x =+  case unsafeCoerce @(Dict (a ~ a)) @(Dict (a ~ b)) Dict of+    Dict -> x++-- | Similar to @SingI []@, but does not require individual elements to be also+-- instance of @SingI@.+class KnownList l where+  klist :: KList l+instance KnownList '[] where+  klist = KNil+instance KnownList xs => KnownList (x ': xs) where+  klist = KCons Proxy Proxy++-- | 'SList' analogy for 'KnownList'.+data KList (l :: [k]) where+  KNil :: KList '[]+  KCons :: KnownList xs => Proxy x -> Proxy xs -> KList (x ': xs)++type RSplit l r = KnownList l++-- | Split a record into two pieces.+rsplit+  :: forall k (l :: [k]) (r :: [k]) f.+      (RSplit l r)+  => Rec f (l ++ r) -> (Rec f l, Rec f r)+rsplit = case klist @l of+  KNil -> (RNil, )+  KCons{} -> \(x :& r) ->+    let (x1, r1) = rsplit r+    in (x :& x1, r1)
+ src/Util/TypeLits.hs view
@@ -0,0 +1,46 @@+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++-- | Re-exports 'GHC.TypeLits', modifying it considering our practices.+module Util.TypeLits+  ( Symbol+  , KnownSymbol+  , AppendSymbol+  , symbolValT+  , symbolValT'++  , TypeError+  , ErrorMessage (..)++  , TypeErrorUnless+  , inTypeErrorUnless+  ) where++import Data.Constraint (Dict(..))+import GHC.TypeLits+import Unsafe.Coerce (unsafeCoerce)++symbolValT :: forall s. KnownSymbol s => Proxy s -> Text+symbolValT = toText . symbolVal++symbolValT' :: forall s. KnownSymbol s => Text+symbolValT' = symbolValT (Proxy @s)++-- | Conditional type error.+--+-- Note that @TypeErrorUnless cond err@ is the same as+-- @If cond () (TypeError err)@, but does not produce type-level error when+-- one of its arguments cannot be deduced.+type family TypeErrorUnless (cond :: Bool) (err :: ErrorMessage) :: Constraint where+  TypeErrorUnless 'True _ = ()+  TypeErrorUnless 'False err = TypeError err++-- | Reify the fact that condition under 'TypeErrorUnless' constraint can be+-- assumed to always hold.+inTypeErrorUnless+  :: forall cond err a.+      TypeErrorUnless cond err+  => (cond ~ 'True => a)+  -> a+inTypeErrorUnless a =+  case unsafeCoerce @(Dict ('True ~ 'True)) @(Dict (cond ~ 'True)) Dict of+    Dict -> a
src/Util/TypeTuple/Instances.hs view
@@ -4,4 +4,4 @@  import Util.TypeTuple.TH -concatMapM deriveRecFromTuple [0..15]+concatMapM deriveRecFromTuple [0..25]
+ src/Util/Typeable.hs view
@@ -0,0 +1,109 @@+-- | Utility for 'Typeable'.+module Util.Typeable+  ( gcastE+  , eqP+  , eqParam1+  , eqParam2+  , eqParam3+  , eqExt+  , compareExt+  ) where++import Data.Typeable ((:~:)(..), Typeable, eqT, gcast, typeRep)+import Fmt ((+||), (||+))++-- | Like 'gcast', casts some container's elements,+-- producing informative error on mismatch.+gcastE :: forall a b t. (Typeable a, Typeable b) => t a -> Either Text (t b)+gcastE = maybeToRight errMsg . gcast+  where+    errMsg = "Type mismatch: expected " +|| typeRep (Proxy @b) ||++                               ", got " +|| typeRep (Proxy @a) ||+ ""++-- | 'Proxy' version of 'eqT'.+eqP :: (Typeable a, Typeable b) => Proxy a -> Proxy b -> Maybe (a :~: b)+eqP (_ :: Proxy a) (_ :: Proxy b) = eqT @a @b++-- | Suppose you have a data type `X` with parameter `a` and you have+-- two values: `x1 :: X a1` and `x2 :: X a2`. You can't compare them+-- using '==', because they have different types. However, you can+-- compare them using 'eqParam1' as long as both parameters are+-- 'Typeable'.+eqParam1 ::+     forall a1 a2 t.+     ( Typeable a1+     , Typeable a2+     , Eq (t a1)+     )+  => t a1+  -> t a2+  -> Bool+eqParam1 t1 t2 = isJust @() $ do+  Refl <- eqT @a1 @a2+  guard (t1 == t2)++-- | Version of 'eqParam1' for types with 2 parameters.+eqParam2 ::+     forall a1 a2 b1 b2 t.+     ( Typeable a1+     , Typeable a2+     , Typeable b1+     , Typeable b2+     , Eq (t a1 b2)+     )+  => t a1 b1+  -> t a2 b2+  -> Bool+eqParam2 t1 t2 = isJust @() $ do+  Refl <- eqT @a1 @a2+  Refl <- eqT @b1 @b2+  guard (t1 == t2)++-- | Version of 'eqParam1' for types with 3 parameters.+eqParam3 ::+     forall a1 a2 b1 b2 c1 c2 t.+     ( Typeable a1+     , Typeable a2+     , Typeable b1+     , Typeable b2+     , Typeable c1+     , Typeable c2+     , Eq (t a1 b1 c1)+     )+  => t a1 b1 c1+  -> t a2 b2 c2+  -> Bool+eqParam3 t1 t2 = isJust @() $ do+  Refl <- eqT @a1 @a2+  Refl <- eqT @b1 @b2+  Refl <- eqT @c1 @c2+  guard (t1 == t2)++-- | Compare two entries of completely different types.+eqExt ::+     forall a1 a2.+     ( Typeable a1+     , Typeable a2+     , Eq a1+     )+  => a1+  -> a2+  -> Bool+eqExt a1 a2 = isJust @() $ do+  Refl <- eqT @a1 @a2+  guard (a1 == a2)++-- | Extension of 'eqExt' to 'compare' function.+compareExt ::+     forall a1 a2.+     ( Typeable a1+     , Typeable a2+     , Ord a1+     )+  => a1+  -> a2+  -> Ordering+compareExt t1 t2 =+  case eqT @a1 @a2 of+    Nothing -> typeRep (Proxy @a1) `compare` typeRep (Proxy @a2)+    Just Refl -> t1 `compare` t2
+ test/Test/Analyzer.hs view
@@ -0,0 +1,53 @@+-- | Tests for analyzer.++module Test.Analyzer+  ( unit_Sample_analyze+  ) where++import Prelude hiding (EQ)++import qualified Data.HashMap.Strict as HM+import Test.HUnit (Assertion, (@?=))++import Michelson.Analyzer+import Michelson.Text+import qualified Michelson.Typed as T+import Michelson.Typed.Instr+import Michelson.Untyped (CT(..))++unit_Sample_analyze :: Assertion+unit_Sample_analyze = analyze sample @?= expectedRes+  where+    expectedRes = AnalyzerRes+      { arConstStrings = HM.fromList [(str1, 3), (str3, 4)]+      , arConstBytes = mempty+      , arErrorTags = HM.fromList [(str1, 2), (str3, 1)]+      }++str1 :: MText+str1 = [mt|aa|]++str3 :: MText+str3 = [mt|bb|]++sample :: T.Contract ('T.Tc 'CString) ('T.Tc 'CString)+sample =+  CAR `Seq` DUP `Seq`+  pushStr str3 `Seq`+  CONCAT `Seq`+  SIZE `Seq` INT `Seq` EQ `Seq`+  IF (LAMBDA (T.VLam . T.RfNormal $ pushStr str3 `Seq` CONCAT) `Seq` DROP)+     (DIP (pushStr str1) `Seq` DROP) `Seq`+  DIP (pushStr str3) `Seq` DROP `Seq`+  pushTrue `Seq`+  IF (pushStr str1 `Seq` FAILWITH)+     pushTrue `Seq`+  IF (pushStr str1 `Seq` PAIR `Seq` FAILWITH)+     Nop `Seq`+  PUSH (T.VPair (T.VC $ T.CvString str3, T.VUnit)) `Seq` FAILWITH+  where+    pushStr :: forall s. MText -> Instr s ('T.Tc 'CString ': s)+    pushStr str = PUSH (T.VC $ T.CvString str)++    pushTrue :: forall s. Instr s ('T.Tc 'CBool ': s)+    pushTrue = PUSH (T.VC $ T.CvBool True)
+ test/Test/Doc.hs view
@@ -0,0 +1,158 @@+{-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}++-- | Tests on automatic documentation generation.++module Test.Doc+  ( test_General_doc_scan+  , test_Dependencies_loops+  , test_Cutting_all_except_doc+  , test_fakeCoerce+  ) where++import qualified Data.Map as Map+import qualified Data.Set as Set+import Data.Typeable (cast)+import Fmt (build)+import Test.HUnit (assertBool, assertFailure, (@?=))+import Test.QuickCheck (total)+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)+import Test.Tasty.QuickCheck (testProperty)++import Lorentz (( # ))+import qualified Lorentz as L+import Michelson.Doc+import Michelson.Typed+import Util.Named++-- General tests on contract doc scan+----------------------------------------------------------------------------++newtype MyType = MyType Integer+  deriving stock (Generic)+  deriving anyclass (IsoValue)++instance TypeHasDoc MyType where+  typeDocMdDescription = ""++data MyGroup = MyGroup Text SubDoc++instance DocItem MyGroup where+  type DocItemPosition MyGroup = 91232+  docItemSectionName = Nothing+  docItemToMarkdown lvl (MyGroup name subDoc) =+    build name <> subDocToMarkdown lvl subDoc++test_General_doc_scan :: [TestTree]+test_General_doc_scan =+  [ testCase "Type declaration is found" $+      let contract = L.doc $ DType (Proxy @MyType)+          doc = L.buildLorentzDoc contract+          mTypeDecls = Map.lookup (docItemPosition @DType) (cdDefinitions doc)+         --- Type declarations should include 'MyType' and 'Integer'+      in fmap length mTypeDecls @?= Just 2++  , testCase "Dependencies of polymorphic types are found" $+      -- There once was a bug which caused, in the following scenario,+      -- 'Integer' type to be found while 'Natural' to be not, doc items+      -- discovery thought that ":!" has already been traversed and didn't+      -- pick its dependencies the second time.+      let contract = L.doc $ L.mkDEntryPointArgSimple @("a" :! Integer, "b" :! Natural)+          doc = L.buildLorentzDoc contract+          defs = cdDefinitionsSet doc+      in do+         assertBool "'Integer' declaration is present" $+            Set.member (SomeDocDefinitionItem $ DType (Proxy @Integer)) defs+         assertBool "'Natural' declaration is present" $+            Set.member (SomeDocDefinitionItem $ DType (Proxy @Natural)) defs++  , testCase "Doc group is handled correctly" $+      let contract = L.docGroup (SomeDocItem . MyGroup "a") $+                     L.doc $ DVersion 1+          doc = L.buildLorentzDoc contract+          contents = cdContents doc+      in case toList contents of+            [SomeDocItem (cast -> Just (MyGroup "a" (SubDoc subcontents))) :| []] ->+               case toList subcontents of+                 [SomeDocItem (cast -> Just (DVersion 1)) :| []] ->+                   pass+                 _ -> assertFailure $ "Unexpected subcontents: " <> show subcontents+            _ -> assertFailure $ "Unexpected contents: " <> show contents+  ]++-- Test on loops on dependency graph of doc items+----------------------------------------------------------------------------++-- | Type, documentation for which somehow depends on itself.+newtype MyLoopedType = MyLoopedType Integer+  deriving stock (Generic)+  deriving anyclass (IsoValue)++instance TypeHasDoc MyLoopedType where+  typeDocDependencies _ = [SomeTypeWithDoc (Proxy @MyLoopedType)]+  typeDocMdDescription = ""++newtype MyMutuallyDependentType1 = MyMutuallyDependentType1 Integer+  deriving stock (Generic)+  deriving anyclass (IsoValue)++newtype MyMutuallyDependentType2 = MyMutuallyDependentType2 Integer+  deriving stock (Generic)+  deriving anyclass (IsoValue)++instance TypeHasDoc MyMutuallyDependentType1 where+  typeDocDependencies _ = [SomeTypeWithDoc (Proxy @MyMutuallyDependentType2)]+  typeDocMdDescription = ""++instance TypeHasDoc MyMutuallyDependentType2 where+  typeDocDependencies _ = [SomeTypeWithDoc (Proxy @MyMutuallyDependentType1)]+  typeDocMdDescription = ""++test_Dependencies_loops :: [TestTree]+test_Dependencies_loops =+  [ testProperty "Type depending on itself" $+      let contract = L.doc $ DType (Proxy @MyLoopedType)+      in total . contractDocToMarkdown $ L.buildLorentzDoc contract+  , testProperty "Mutually dependent types" $+      let contract = L.doc $ DType (Proxy @MyMutuallyDependentType1)+      in total . contractDocToMarkdown $ L.buildLorentzDoc contract+  ]++-- Functions semantics+----------------------------------------------------------------------------++test_Cutting_all_except_doc :: [TestTree]+test_Cutting_all_except_doc =+  [ testCase "Cleaning simple code" $+      let contract =+            L.doc (DVersion 1) #+            L.push True #+            L.if_ (L.contractName "aaa" $ L.doc $ DDescription "a") (L.sender # L.drop)+            :: '[] L.:-> '[]+          cutContract =+            L.doc (DVersion 1) #+            L.contractName "aaa" (L.doc $ DDescription "a")+      in L.renderLorentzDoc (L.cutLorentzNonDoc contract)+         @?=+         L.renderLorentzDoc cutContract++  , testCase "DocGroup is handled correctly" $+      let contract =+            L.docGroup (SomeDocItem . MyGroup "b") $+              L.doc (DVersion 1) # L.nop+          cutContract =+            L.docGroup (SomeDocItem . MyGroup "b") $+              L.doc (DVersion 1)+      in L.renderLorentzDoc (L.cutLorentzNonDoc contract)+         @?=+         L.renderLorentzDoc cutContract+  ]++test_fakeCoerce :: [TestTree]+test_fakeCoerce =+  [ testCase "Does not truncate the following documentation" $+      let contract = L.doc (DVersion 1) :: '[] L.:-> '[]+      in L.renderLorentzDoc (L.fakeCoerce # contract)+         @?=+         L.renderLorentzDoc contract+  ]
+ test/Test/EntryPoints.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE DeriveAnyClass #-}++-- | Tests for Lorentz compilation which uses 'LorentzCompilationWay'.+module Test.EntryPoints+  ( test_EpAddress+  , test_ParamNotes+  , test_ParamEpError+  ) where++import Prelude hiding (or)++import Data.Default (def)+import Fmt (pretty)+import Test.HUnit (assertBool, (@?=))+import Test.QuickCheck+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (testCase)++import Michelson.Typed+import Michelson.Untyped (ann, noAnn)+import Tezos.Address+import Util.Test.Arbitrary++import Test.Util.QuickCheck++test_EpAddress :: [TestTree]+test_EpAddress =+  [ testGroup "Parsing" $+    [ testCase "Simple entrypoint" $+        parseEpAddress (formatAddress addr <> "%ab")+          @?= Right (EpAddress addr (EpNameUnsafe "ab"))++    , testCase "No entrypoint" $+        parseEpAddress (formatAddress addr)+          @?= Right (EpAddress addr def)++    , testCase "Weird entrypoint" $+        parseEpAddress (formatAddress addr <> "%a%b")+          @?= Right (EpAddress addr (EpNameUnsafe "a%b"))+    ]++  , testGroup "parse . format = pure"+    [ roundtripTestSTB formatEpAddress parseEpAddress ]+  ]+  where+    addr = runGen 123 arbitrary++test_ParamNotes :: [TestTree]+test_ParamNotes =+  [ testGroup "Duplications are handled" $+    [ testCase "One duplicated entrypoint" $+        mkParamNotes (or "a" "a" prim prim)+          @?= Left (ParamEpDuplicatedNames (EpNameUnsafe "a" :| []))+    , testCase "Several duplicated entrypoint" $+        mkParamNotes (or "" "" (or "a" "b" prim prim) (or "b" "a" prim prim))+          @?= Left (ParamEpDuplicatedNames (EpNameUnsafe "a" :| [EpNameUnsafe "b"]))+    , testCase "Duplicated default entrypoint" $+        mkParamNotes (or "default" "default" prim prim)+          @?= Left (ParamEpDuplicatedNames (NoEpName :| []))+    ]++  , testGroup "All entrypoints callable check" $+    [ testCase "Non-callable entrypoint is detected in simple case" $+        mkParamNotes (or "default" "" prim (or "" "q" prim prim))+          @?= Left (ParamEpUncallableArm [AcRight, AcLeft])+    , testCase "Non-callable entrypoint is detected in complex case" $+        mkParamNotes (or "a" "" prim (or "" "default" (or "b" "" prim prim) prim))+          @?= Left (ParamEpUncallableArm [AcRight, AcLeft, AcRight])++    , testCase "Having all leaves named is enough for callability" $+        mkParamNotes (or "default" "" prim (or "q" "" prim (or "a" "b" prim prim)))+          & assertBool "All arms should've considered callable" . isRight+    , testCase "Having all leaves named is enough for callability" $+        mkParamNotes (or "default" "a" prim (or "" "" prim (or "" "" prim prim)))+          & assertBool "All arms should've considered callable" . isRight+    ]+  ]+  where+    or a1 a2 = NTOr noAnn (ann a1) (ann a2)+    prim = NTKey noAnn++test_ParamEpError :: [TestTree]+test_ParamEpError =+  [ testGroup "Buildable instance"+    [ testCase "Duplicated entrypoints error" $+        pretty @_ @Text (ParamEpDuplicatedNames $ EpNameUnsafe "a" :| [EpNameUnsafe ""])+        @?= "Duplicated entrypoint names: 'a', '<default>'"+    , testCase "Uncallable arms error" $+        pretty @_ @Text (ParamEpUncallableArm [AcLeft, AcRight])+        @?= "Due to presence of 'default' entrypoint, one of contract \"arms\" \+            \cannot be called: \"left - right\" (in top-to-bottom order)"+    ]+  ]
test/Test/Ext.hs view
@@ -1,38 +1,40 @@ module Test.Ext-  ( spec_Ext_Intepreter+  ( test_PRINT_and_TEST_ASSERT   , test_STACKTYPE   ) where  import Data.Default (def)-import Test.Hspec (Spec, describe, it, shouldSatisfy)+import Test.Hspec.Expectations (shouldSatisfy) import Test.HUnit (Assertion, assertFailure) import Test.Tasty (TestTree) import Test.Tasty.HUnit (testCase)  import Michelson.Interpret (InterpreterState(..), MorleyLogs(..), interpret)-import Michelson.Test (specWithTypedContract)+import Michelson.Test (concatTestTrees, testTreesWithTypedContract) import Michelson.Test.Dummy (dummyContractEnv) import Michelson.TypeCheck (HST(..), SomeHST(..), runTypeCheck, typeCheckExt, typeCheckList)-import Michelson.Typed (CValue(..), extractNotes, fromUType, withSomeSingT)+import Michelson.Typed (CValue(..), withUType) import qualified Michelson.Typed as T import Michelson.Untyped   (CT(..), ExpandedExtInstr, ExtInstrAbstract(..), StackTypePattern(..), T(..), TyVar(..),   Type(..), ann, noAnn) -spec_Ext_Intepreter :: Spec-spec_Ext_Intepreter = describe "PRINT/TEST_ASSERT tests" $ do-  specWithTypedContract "contracts/testassert_square.mtz" $-    testAssertSquareSpec-  specWithTypedContract "contracts/testassert_square2.mtz" $-    testAssertSquareSpec+test_PRINT_and_TEST_ASSERT :: IO [TestTree]+test_PRINT_and_TEST_ASSERT = concatTestTrees+  [ testTreesWithTypedContract "contracts/testassert_square.mtz" $+    testAssertSquareImpl+  , testTreesWithTypedContract "contracts/testassert_square2.mtz" $+    testAssertSquareImpl+  ]   where-    testAssertSquareSpec c = do-      it "TEST_ASSERT assertion passed" $ do+    testAssertSquareImpl c = pure+      [ testCase "TEST_ASSERT assertion passed" $ do         runTest True c 100 100         runTest True c 1 1-      it "TEST_ASSERT assertion failed" $ do+      , testCase "TEST_ASSERT assertion failed" $ do         runTest False c 0 100         runTest False c -1 -2+      ]      runTest corr contract x y = do       let x' = T.VC $ T.CvInt x :: T.Value ('T.Tc 'T.CInt)@@ -71,15 +73,13 @@     test8 = (STACKTYPE p3, convertToHST [t1])     test9 = (STACKTYPE p2, convertToHST [t1, t3]) -    t1 = Type (TOption (ann "f") (Type TKey (ann "key"))) (ann "opt")+    t1 = Type (TOption (Type TKey (ann "key"))) (ann "opt")     t2 = Type (TPair (ann "f") (ann "s") (Type TUnit "x") (Type TSignature "s")) noAnn     t3 = Type (Tc CInt) (ann "tint")      convertToHST :: [Type] -> SomeHST     convertToHST [] = SomeHST SNil-    convertToHST (t : ts) = withSomeSingT (fromUType t) $ \sing ->-      let nt = fromRight (error "unexpected trouble with extracting annotations")-                         (extractNotes t sing) in+    convertToHST (t : ts) = withUType t $ \((sing :: T.Sing t), (nt :: T.Notes t)) ->       case convertToHST ts of         SomeHST is -> SomeHST ((sing, nt, noAnn) ::& is) 
+ test/Test/Integrational.hs view
@@ -0,0 +1,26 @@+-- | Tests for integrational testing machinery.+module Test.Integrational+  ( spec_Chain_id+  ) where++import Test.Hspec (Spec, it)++import Lorentz (( # ))+import qualified Lorentz as L+import Lorentz.Test+import Tezos.Core++spec_Chain_id :: Spec+spec_Chain_id = do+  it "Chain id can be set" $+    integrationalTestExpectation $ do+      let code = L.drop # L.chainId # L.nil # L.pair+      let chainId = mkChainIdUnsafe "aaaa"++      contract <- lOriginate code "" dummyChainId (toMutez 50)++      setChainId chainId+      lCall contract ()++      validate . Right $+        lExpectStorageConst contract chainId
test/Test/Interpreter.hs view
@@ -1,182 +1,277 @@ {-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}  module Test.Interpreter-  ( spec_Interpreter+  ( test_basic5+  , test_increment+  , test_fail+  , test_mutez_add_overflow+  , test_mutez_sub_overflow+  , test_basic1+  , test_lsl+  , test_lsr+  , test_FAILWITH+  , test_STEPS_TO_QUOTA+  , test_gas_exhaustion+  , test_add1_list+  , test_mkStackRef+  , test_Sum_types+  , test_Product_types+  , test_split_bytes+  , test_split_string_simple+  , test_complex_strings+  , test_contract_instr_on_implicit+  , test_APPLY+  , test_Entry_points_lookup+  , test_Entry_points_calling   ) where  import Data.Singletons (SingI)+import qualified Data.Map as Map import Fmt (pretty, (+|), (|+))-import Test.Hspec (Expectation, Spec, describe, expectationFailure, it, shouldBe, shouldSatisfy)-import Test.Hspec.QuickCheck (prop)+import Test.Hspec.Expectations (Expectation, expectationFailure, shouldBe, shouldSatisfy)+import Test.HUnit (Assertion, assertFailure, (@?=)) import Test.QuickCheck (Property, label, (.&&.), (===))+import Text.Hex (decodeHex)+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (testCase)+import Test.Tasty.QuickCheck (testProperty)+import Util.Named ((.!)) -import Lorentz (( # ))+import Lorentz (( # ), Lambda)+import Lorentz.Test.Integrational (tTransfer, tExpectStorageConst)+import Michelson.Test.Integrational (originate) import qualified Lorentz as L+import Lorentz.Run import Michelson.Interpret   (ContractEnv(..), ContractReturn, MichelsonFailed(..), RemainingSteps, interpret)-import Michelson.Test (ContractPropValidator, contractProp, specWithTypedContract)+import Michelson.Test+  (ContractPropValidator, concatTestTrees, contractProp, testTreesWithUntypedContract, testTreesWithTypedContract) import Michelson.Test.Dummy (dummyContractEnv)+import Michelson.Test.Integrational (integrationalTestExpectation,+                                     genesisAddress, validate)+import Tezos.Crypto+import Tezos.Address+import Tezos.Core import Michelson.Test.Util (failedProp)-import Michelson.Typed (CT(..), CValue(..), IsoValue(..), T(..)) import Michelson.Text+import Michelson.Typed (CT(..), CValue(..), IsoValue(..), T(..))+import qualified Michelson.Untyped as U import qualified Michelson.Typed as T-import Test.Interpreter.A1.Feather (featherSpec)-import Test.Interpreter.CallSelf (selfCallerSpec)-import Test.Interpreter.Compare (compareSpec)-import Test.Interpreter.Conditionals (conditionalsSpec)-import Test.Interpreter.ContractOp (contractOpSpec)-import Test.Interpreter.EnvironmentSpec (environmentSpec)-import Test.Interpreter.StringCaller (stringCallerSpec) -spec_Interpreter :: Spec-spec_Interpreter = do-  let contractResShouldBe (res, _) expected =-        case res of-          Left err -> expectationFailure $ "Unexpected failure: " <> pretty err-          Right (_ops, v) -> v `shouldBe` expected--  specWithTypedContract "contracts/basic5.tz" $ \contract ->-    it "Basic test" $-      interpret contract T.VUnit (toVal [1 :: Integer]) dummyContractEnv-        `contractResShouldBe` (toVal [13 :: Integer, 100])+test_basic5 :: IO [TestTree]+test_basic5 =+  testTreesWithTypedContract "contracts/basic5.tz" $ \contract -> pure+  [ testCase "Basic test" $+      contractProp @() @[Integer] contract (validateStorageIs [13 :: Integer, 100])+        dummyContractEnv () [1]+  ] -  specWithTypedContract "contracts/increment.tz" $ \contract ->-    it "Basic test" $-      interpret contract T.VUnit (toVal @Integer 23) dummyContractEnv-        `contractResShouldBe` (toVal @Integer 24)+test_increment :: IO [TestTree]+test_increment =+  testTreesWithTypedContract "contracts/increment.tz" $ \contract -> pure+  [ testCase "Basic test" $+      contractProp @() @Integer contract (validateStorageIs @Integer 24)+        dummyContractEnv () 23+  ] -  specWithTypedContract "contracts/tezos_examples/fail.tz" $ \contract ->-    it "Fail test" $+test_fail :: IO [TestTree]+test_fail =+  testTreesWithTypedContract "contracts/tezos_examples/macros/fail.tz" $ \contract -> pure+  [ testCase "Fail test" $       interpret contract T.VUnit T.VUnit dummyContractEnv         `shouldSatisfy` (isLeft . fst)+  ] -  specWithTypedContract "contracts/mutez_add_overflow.tz" $ \contract ->-    it "Mutez add overflow test" $+test_mutez_add_overflow :: IO [TestTree]+test_mutez_add_overflow =+  testTreesWithTypedContract "contracts/mutez_add_overflow.tz" $ \contract -> pure+  [ testCase "Mutez add overflow test" $       interpret contract T.VUnit T.VUnit dummyContractEnv         `shouldSatisfy` (isLeft . fst)+  ] -  specWithTypedContract "contracts/mutez_sub_underflow.tz" $ \contract ->-    it "Mutez sub underflow test" $+test_mutez_sub_overflow :: IO [TestTree]+test_mutez_sub_overflow =+  testTreesWithTypedContract "contracts/mutez_sub_underflow.tz" $ \contract -> pure+  [ testCase "Mutez sub underflow test" $       interpret contract T.VUnit T.VUnit dummyContractEnv         `shouldSatisfy` (isLeft . fst)+  ] -  specWithTypedContract "contracts/basic1.tz" $ \contract -> do-    prop "Random check" $ \input ->+test_basic1 :: IO [TestTree]+test_basic1 =+  testTreesWithTypedContract "contracts/basic1.tz" $ \contract -> pure+  [ testProperty "Random check" $ \input ->       contractProp @_ @[Integer] contract (validateBasic1 input)       dummyContractEnv () input+  ] -  specWithTypedContract "contracts/lsl.tz" $ \contract -> do-    it "LSL shouldn't overflow test" $-      interpret contract (toVal @Natural 5) (toVal @Natural 2) dummyContractEnv-        `contractResShouldBe` (toVal @Natural 20)-    it "LSL should overflow test" $+test_lsl :: IO [TestTree]+test_lsl =+  testTreesWithTypedContract "contracts/lsl.tz" $ \contract -> pure+  [ testCase "LSL shouldn't overflow test" $+      contractProp @Natural @Natural contract (validateStorageIs @Natural 20)+        dummyContractEnv 5 2+  , testCase "LSL should overflow test" $       interpret contract (toVal @Natural 5) (toVal @Natural 257) dummyContractEnv         `shouldSatisfy` (isLeft . fst)+  ] -  specWithTypedContract "contracts/lsr.tz" $ \contract -> do-    it "LSR shouldn't underflow test" $-      interpret contract (toVal @Natural 30) (toVal @Natural 3) dummyContractEnv-        `contractResShouldBe` (toVal @Natural 3)-    it "LSR should underflow test" $+test_lsr :: IO [TestTree]+test_lsr =+  testTreesWithTypedContract "contracts/lsr.tz" $ \contract -> pure+  [ testCase "LSR shouldn't underflow test" $+      contractProp @Natural @Natural contract (validateStorageIs @Natural 3)+        dummyContractEnv 30 3+  , testCase "LSR should underflow test" $       interpret contract (toVal @Natural 1000) (toVal @Natural 257) dummyContractEnv         `shouldSatisfy` (isLeft . fst)+  ] -  describe "FAILWITH" $ do-    specWithTypedContract "contracts/failwith_message.tz" $ \contract ->-      it "Failwith message test" $ do+test_FAILWITH :: IO [TestTree]+test_FAILWITH = concatTestTrees+  [ testTreesWithTypedContract "contracts/failwith_message.tz" $ \contract ->+    pure+    [ testCase "Failwith message test" $ do         let msg = [mt|An error occurred.|] :: MText-        contractProp contract (validateMichelsonFailsWith msg) dummyContractEnv msg ()--    specWithTypedContract "contracts/failwith_message2.tz" $ \contract -> do-        it "Conditional failwith message test" $ do-          let msg = [mt|An error occurred.|]-          contractProp contract (validateMichelsonFailsWith msg) dummyContractEnv (True, msg) ()--        it "Conditional success test" $ do-          let param = (False, [mt|Err|] :: MText)-          contractProp contract validateSuccess dummyContractEnv param ()+        contractProp contract (validateMichelsonFailsWith msg) dummyContractEnv+          msg ()+    ]+  , testTreesWithTypedContract "contracts/failwith_message2.tz" $ \contract ->+    pure+    [ testCase "Conditional failwith message test" $ do+        let msg = [mt|An error occurred.|]+        contractProp contract (validateMichelsonFailsWith msg) dummyContractEnv+          (True, msg) () -  compareSpec-  conditionalsSpec-  stringCallerSpec-  selfCallerSpec-  environmentSpec-  contractOpSpec-  featherSpec+    , testCase "Conditional success test" $ do+        let param = (False, [mt|Err|] :: MText)+        contractProp contract validateSuccess dummyContractEnv param ()+    ]+  ] -  specWithTypedContract "contracts/steps_to_quota_test1.tz" $ \contract -> do-    it "Amount of steps should reduce" $ do+test_STEPS_TO_QUOTA :: IO [TestTree]+test_STEPS_TO_QUOTA = concatTestTrees+  [ testTreesWithTypedContract "contracts/steps_to_quota_test1.tz" $ \contract ->+    pure+    [ testCase "Amount of steps should decrease (1)" $ do       validateStepsToQuotaTest         (interpret contract T.VUnit (T.VC (CvNat 0)) dummyContractEnv) 4--  specWithTypedContract "contracts/steps_to_quota_test2.tz" $ \contract -> do-    it "Amount of steps should reduce" $ do+    ]+  , testTreesWithTypedContract "contracts/steps_to_quota_test2.tz" $ \contract ->+    pure+    [ testCase "Amount of steps should decrease (2)" $ do       validateStepsToQuotaTest         (interpret contract T.VUnit (T.VC (CvNat 0)) dummyContractEnv) 8+    ]+  ] -  specWithTypedContract "contracts/gas_exhaustion.tz" $ \contract -> do-    it "Contract should fail due to gas exhaustion" $ do+test_gas_exhaustion :: IO [TestTree]+test_gas_exhaustion =+  testTreesWithTypedContract "contracts/gas_exhaustion.tz" $ \contract -> pure+  [ testCase "Contract should fail due to gas exhaustion" $ do       let dummyStr = toVal [mt|x|]       case fst $ interpret contract dummyStr dummyStr dummyContractEnv of-        Right _ -> expectationFailure "expecting contract to fail"+        Right _ -> assertFailure "expecting contract to fail"         Left MichelsonGasExhaustion -> pass-        Left _ -> expectationFailure "expecting another failure reason"+        Left _ -> assertFailure "expecting another failure reason"+  ] -  specWithTypedContract "contracts/tezos_examples/add1_list.tz" $ \contract -> do-    let-      validate ::-        [Integer] -> ContractPropValidator (ToT [Integer]) Property-      validate param (res, _) =-        case res of-          Left failed -> failedProp $-            "add1_list unexpectedly failed: " <> pretty failed-          Right (fromVal . snd -> finalStorage) ->-            map succ param === finalStorage-    prop "Random check" $ \param ->-      contractProp contract (validate param) dummyContractEnv param param+test_add1_list :: IO [TestTree]+test_add1_list =+  testTreesWithTypedContract "contracts/tezos_examples/attic/add1_list.tz" $ \contract ->+  let+    doValidate ::+      [Integer] -> ContractPropValidator (ToT [Integer]) Property+    doValidate param (res, _) =+      case res of+        Left failed -> failedProp $+          "add1_list unexpectedly failed: " <> pretty failed+        Right (fromVal . snd -> finalStorage) ->+          map succ param === finalStorage+  in pure+  [ testProperty "Random check" $ \param ->+      contractProp contract (doValidate param) dummyContractEnv param param+  ] -  it "mkStackRef does not segfault" $ do+test_mkStackRef :: TestTree+test_mkStackRef =+  testCase "does not segfault" $ do     let contract = L.drop # L.push () # L.dup # L.printComment (L.stackRef @1)                           # L.drop # L.nil @T.Operation # L.pair-    contractProp (L.compileLorentzContract @() contract) (isRight . fst) dummyContractEnv () ()--  specWithTypedContract "contracts/union.mtz" $ \contract -> do-    describe "Union corresponds to Haskell types properly" $ do-      let caseTest param =-            contractProp contract validateSuccess dummyContractEnv param ()--      it "Case 1" $ caseTest (Case1 3)-      it "Case 2" $ caseTest (Case2 [mt|a|])-      it "Case 3" $ caseTest (Case3 $ Just [mt|b|])-      it "Case 4" $ caseTest (Case4 $ Left [mt|b|])-      it "Case 5" $ caseTest (Case5 [[mt|q|]])--  specWithTypedContract "contracts/case.mtz" $ \contract -> do-    describe "CASE instruction" $ do-      let caseTest param expectedStorage =-            contractProp contract (validateStorageIs @MText expectedStorage)-              dummyContractEnv param [mt||]+    contractProp (T.fcCode $ compileLorentzContract @() contract)+      (flip shouldSatisfy isRight . fst) dummyContractEnv () () -      it "Case 1" $ caseTest (Case1 5) [mt|int|]-      it "Case 2" $ caseTest (Case2 [mt|a|]) [mt|string|]-      it "Case 3" $ caseTest (Case3 $ Just [mt|aa|]) [mt|aa|]-      it "Case 4" $ caseTest (Case4 $ Right [mt|b|]) [mt|or string string|]-      it "Case 5" $ caseTest (Case5 $ [[mt|a|], [mt|b|]]) [mt|ab|]+test_Sum_types :: IO [TestTree]+test_Sum_types = concatTestTrees+  [ testTreesWithTypedContract "contracts/union.mtz" $ \contract -> pure+    [ testGroup "union.mtz: union corresponds to Haskell types properly" $+        let caseTest param =+              contractProp contract validateSuccess dummyContractEnv param ()+        in+        [ testCase "Case 1" $ caseTest (Case1 3)+        , testCase "Case 2" $ caseTest (Case2 [mt|a|])+        , testCase "Case 3" $ caseTest (Case3 $ Just [mt|b|])+        , testCase "Case 4" $ caseTest (Case4 $ Left [mt|b|])+        , testCase "Case 5" $ caseTest (Case5 [[mt|q|]])+        ]+    ]+  , testTreesWithTypedContract "contracts/case.mtz" $ \contract -> pure+    [ testGroup "CASE instruction" $+        let caseTest param expectedStorage =+              contractProp contract (validateStorageIs @MText expectedStorage)+                dummyContractEnv param [mt||]+        in+        [ testCase "Case 1" $ caseTest (Case1 5) [mt|int|]+        , testCase "Case 2" $ caseTest (Case2 [mt|a|]) [mt|string|]+        , testCase "Case 3" $ caseTest (Case3 $ Just [mt|aa|]) [mt|aa|]+        , testCase "Case 4" $ caseTest (Case4 $ Right [mt|b|]) [mt|or string string|]+        , testCase "Case 5" $ caseTest (Case5 $ [[mt|a|], [mt|b|]]) [mt|ab|]+        ]+    ]+  , testTreesWithTypedContract "contracts/tag.mtz" $ \contract -> pure+    [ testCase "TAG instruction" $+        let expected = mconcat [[mt|unit|], [mt|o|], [mt|ab|], [mt|nat|], [mt|int|]]+        in contractProp contract (validateStorageIs expected) dummyContractEnv () [mt||]+    ]+  ] -  specWithTypedContract "contracts/tag.mtz" $ \contract -> do-    it "TAG instruction" $-      let expected = mconcat [[mt|unit|], [mt|o|], [mt|ab|], [mt|nat|], [mt|int|]]-      in contractProp contract (validateStorageIs expected) dummyContractEnv-         () [mt||]+test_Product_types :: IO [TestTree]+test_Product_types = concatTestTrees+  [ testTreesWithTypedContract "contracts/access.mtz" $ \contract -> pure+    [ testCase "ACCESS instruction" $+        contractProp @Tuple1 contract validateSuccess dummyContractEnv+          (1, [mt|a|], Just [mt|a|], Right [mt|a|], [[mt|a|]]) ()+    ]+  , testTreesWithTypedContract "contracts/set.mtz" $ \contract -> pure+    [ testCase "SET instruction" $+      let expected = (2, [mt|za|], Just [mt|wa|], Right [mt|ya|], [[mt|ab|]]) :: Tuple1+      in contractProp @_ @Tuple1 contract (validateStorageIs expected)+        dummyContractEnv () (1, [mt|a|], Just [mt|a|], Right [mt|a|], [[mt|a|], [mt|b|]])+    ]+  , testTreesWithTypedContract "contracts/construct.mtz" $ \contract -> pure+    [ testCase "CONSTRUCT instruction" $+      let expected = (1, [mt|a|], Just [mt|b|], Left [mt|q|], []) :: Tuple1+      in contractProp @_ @Tuple1 contract (validateStorageIs expected)+        dummyContractEnv () (0, [mt||], Nothing, Right [mt||], [])+    ]+  ] -  specWithTypedContract "contracts/tezos_examples/split_bytes.tz" $ \contract -> do-    it "splits given byte sequence into parts" $+test_split_bytes :: IO [TestTree]+test_split_bytes =+  testTreesWithTypedContract "contracts/tezos_examples/opcodes/split_bytes.tz" $ \contract ->+  pure+  [ testCase "splits given byte sequence into parts" $       let expected = ["\11", "\12", "\13"] :: [ByteString]       in contractProp contract (validateStorageIs expected) dummyContractEnv          ("\11\12\13" :: ByteString) ([] :: [ByteString])+  ] -  specWithTypedContract "contracts/split_string_simple.tz" $ \contract -> do-    it "applies SLICE instruction" $ do+test_split_string_simple :: IO [TestTree]+test_split_string_simple =+  testTreesWithTypedContract "contracts/split_string_simple.tz" $ \contract ->+  pure+  [ testCase "applies SLICE instruction" $ do       let         oneTest :: Natural -> Natural -> MText -> Maybe MText -> Expectation         oneTest o l str expected =@@ -194,12 +289,17 @@       oneTest 2 2 [mt|abc|] Nothing       oneTest 1 1 [mt|a""|] (Just [mt|"|])       oneTest 1 2 [mt|a\n|] Nothing+  ] -  specWithTypedContract "contracts/complex_strings.tz" $ \contract ->-    prop "Complex string" $+test_complex_strings :: IO [TestTree]+test_complex_strings =+  testTreesWithTypedContract "contracts/complex_strings.tz" $ \contract ->+  pure+  [ testCase "ComplexString" $       contractProp contract       (validateStorageIs [mt|text: "aa" \\\n|])       dummyContractEnv [mt|text: |] [mt||]+  ]  data Union1   = Case1 Integer@@ -210,18 +310,138 @@   deriving stock (Generic)   deriving anyclass (IsoValue) -validateSuccess :: ContractPropValidator st Expectation+type Tuple1 = (Integer, MText, Maybe MText, Either MText MText, [MText])++test_contract_instr_on_implicit :: IO [TestTree]+test_contract_instr_on_implicit =+  testTreesWithTypedContract "contracts/contract_instr_unit.tz" $ \contractGood ->+  testTreesWithTypedContract "contracts/contract_instr_nonunit.tz" $ \contractBad ->+  pure+  [ testCase "CONTRACT instruction succeeds on implicit accounts" $+      contractProp contractGood validateSuccess dummyContractEnv addr ()++  , testCase "CONTRACT instruction considers implicit accounts as unit-parametrized" $+      contractProp contractBad (validateMichelsonFailsWith [mt|No such contract|])+        dummyContractEnv addr ()+  ]+  where+    addr = mkKeyAddress . toPublic $ detSecretKey "sfsdfsdf"++test_APPLY :: IO [TestTree]+test_APPLY =+  testTreesWithTypedContract "contracts/apply.tz" $ \applyContract ->+  testTreesWithTypedContract "contracts/partially-applied-lambda-packed.tz" $ \partApplyContract ->+  pure+  [ testCase "Basic test" $+      contractProp @(Lambda (Integer, Integer) Integer) @Integer+        applyContract (validateStorageIs @Integer 2)+        dummyContractEnv (L.unpair # L.sub) 0+  , testCase "Partially applied lambda packed" $+      let expected = decodeHex "05020000000f0743035b0005034202000000020316"+                  ?: error "Bad bytes"+      in contractProp @() @ByteString+          partApplyContract (validateStorageIs @ByteString expected)+          dummyContractEnv () ""+  ]+++-- TODO [TM-280] Move to separate module+test_Entry_points_lookup :: IO [TestTree]+test_Entry_points_lookup =+  testTreesWithTypedContract (dir <> "call1.mtz") $ \call1 ->+  testTreesWithTypedContract (dir <> "call2.mtz") $ \call2 ->+  testTreesWithTypedContract (dir <> "call3.mtz") $ \call3 ->+  testTreesWithTypedContract (dir <> "call4.mtz") $ \call4 ->+  testTreesWithTypedContract (dir <> "call5.mtz") $ \call5 ->+  testTreesWithTypedContract (dir <> "call6.mtz") $ \call6 ->+  testTreesWithTypedContract (dir <> "call7.mtz") $ \call7 ->+  pure+  [ testGroup "Calling contract without default entrypoint"+    [ testCase "Calling default entrypoint refers to the root" $+        checkProp call1 validateSuccess (addr "simple")+    , testCase "Calling some entrypoint refers this entrypoint" $+        checkProp call7 validateSuccess (addr "simple")+    ]+  , testGroup "Calling contract with default entrypoint"+    [ testCase "Calling default entrypoint works" $+        checkProp call2 validateSuccess (addr "def")+    ]+  , testGroup "Common failures"+    [ testCase "Fails on type mismatch" $+        checkProp call1 validateFailure (addr "def")+    , testCase "Fails on entrypoint not found" $+        checkProp call3 validateFailure (addr "simple")+    ]+  , testGroup "Referring entrypoints groups"+    [ testCase "Can refer entrypoint group" $+        checkProp call4 validateSuccess (addr "complex")+    , testCase "Works with annotations" $+        checkProp call5 validateSuccess (addr "complex")+    , testCase "Does not work on annotations mismatch in 'contract' type argument" $+        checkProp call6 validateFailure (addr "complex")+    ]+  ]+  where+    checkProp contract validator callee =+      contractProp @Address @()+        contract validator+        dummyContractEnv{ ceContracts = Map.fromList env }+        callee ()+    validateFailure = validateMichelsonFailsWith ()++    dir = "contracts/entrypoints/"+    contractSimpleTy =+      U.Type (U.TOr (U.ann "a") (U.ann "b") (U.Type U.Tint U.noAnn) (U.Type U.Tnat U.noAnn))+             U.noAnn+    contractComplexTy =+      U.Type (U.TOr (U.ann "s") (U.ann "t") (U.Type U.Tstring U.noAnn) contractSimpleTy)+             U.noAnn+    contractWithDefTy =+      U.Type (U.TOr (U.ann "a") (U.ann "default") (U.Type U.Tnat U.noAnn) (U.Type U.Tstring U.noAnn))+             U.noAnn+    addr = mkContractAddressRaw+    env =+      [ (mkContractHashRaw "simple", contractSimpleTy)+      , (mkContractHashRaw "complex", contractComplexTy)+      , (mkContractHashRaw "def", contractWithDefTy)+      ]++test_Entry_points_calling :: IO [TestTree]+test_Entry_points_calling =+  testTreesWithUntypedContract (dir <> "call1.mtz") $ \call1 ->+  testTreesWithUntypedContract (dir <> "contract1.mtz") $ \contract1 ->+  pure+  [ testCase "Calling some entrypoint" $+      integrationalTestExpectation $ do+        -- TODO [TM-280]: Use 'tOriginate' at least.+        -- Currently it's not possible, in untyped -> typed conversion we loose+        -- information about parameter annotations; to fix this, need to replace+        -- all 'T.Contract' with 'T.FullContract'.+        callerRef <- originate call1 "caller" (T.untypeValue $ toVal ()) (toMutez 100)+        targetRef <- originate contract1 "target" (T.untypeValue $ toVal @Integer 0) (toMutez 100)++        tTransfer (#from .! genesisAddress) (#to .! callerRef) (toMutez 1) (toVal targetRef)++        validate . Right $+          tExpectStorageConst targetRef (toVal @Integer 5)+  ]+  where+    dir = "contracts/entrypoints/"++----------------------------------------------------------------------------++validateSuccess :: HasCallStack => ContractPropValidator st Expectation validateSuccess (res, _) = res `shouldSatisfy` isRight  validateStorageIs   :: IsoValue st-  => st -> ContractPropValidator (ToT st) Expectation+  => st -> ContractPropValidator (ToT st) Assertion validateStorageIs expected (res, _) =   case res of     Left err ->-      expectationFailure $ "Unexpected interpretation failure: " +| err |+ ""+      assertFailure $ "Unexpected interpretation failure: " +| err |+ ""     Right (_ops, got) ->-      got `shouldBe` toVal expected+      got @?= toVal expected  validateBasic1   :: [Integer] -> ContractPropValidator ('TList ('Tc 'CInt)) Property@@ -232,7 +452,7 @@ validateBasic1 _ (Left e, _) = failedProp $ show e  validateStepsToQuotaTest ::-     ContractReturn ('Tc 'CNat) -> RemainingSteps -> Expectation+  ContractReturn ('Tc 'CNat) -> RemainingSteps -> Expectation validateStepsToQuotaTest res numOfSteps =   case fst res of     Right ([], T.VC (CvNat x)) ->
− test/Test/Interpreter/A1/Feather.hs
@@ -1,237 +0,0 @@-{-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}---- | Tests for feathering as described in TZIP-A1.--module Test.Interpreter.A1.Feather-  ( featherSpec-  ) where--import Control.Lens (makeLenses, (%=), (+=), (-=), (.=))-import Control.Monad.Except (Except, runExcept, throwError)-import Data.Singletons (SingI)-import Test.Hspec (Spec)-import Test.Hspec.QuickCheck (prop)-import Test.QuickCheck (Gen, arbitrary, forAll, frequency, listOf, suchThat)-import Test.QuickCheck.Arbitrary.Generic (genericArbitrary)-import Test.QuickCheck.Instances.Natural ()--import Lorentz (View, Void_)-import qualified Lorentz as L-import Lorentz.Test-import Michelson.Interpret (MichelsonFailed(..))-import Michelson.Interpret.Pack (packValue')-import Michelson.Test-import qualified Michelson.Typed as T-import qualified Michelson.Untyped as U-import Tezos.Address-import Tezos.Core-import Tezos.Crypto-import Util.Named--data Outcome = Outcome-  { _oCounter :: !Natural-  , _oList :: ![Natural]-  , _oSum :: !Natural-  }--makeLenses ''Outcome--featherSpec :: Spec-featherSpec =-  specWithContractL "contracts/A1/counter.mtz" $ \counter ->-  specWithContractL "contracts/A1/feather.mtz" $ \feather ->-  specWithContractL "contracts/A1/caller_add.mtz" $ \callerAdd ->-  specWithContractL "contracts/A1/caller_append.mtz" $ \callerAppend ->-  specImpl counter feather callerAdd callerAppend--data CounterParameter-  = AntibumpCounter-  | BumpCounter-  | ResetCounter Natural-  | GetCount (View () Natural)-  | HashCount (Void_ () ByteString)-  deriving stock Generic-  deriving anyclass T.IsoValue-type CounterStorage = Natural--type FeatherParameter = ((), Maybe Natural)-type FeatherStorage = (Address, Maybe Address)--type CallerParameter = Either Natural ()-type CallerAddStorage = (Natural, Address)-type CallerAppendStorage = ([Natural], Address)---- Actions that can be performed by this scenario.-data Action-  = Antibump-  -- ^ Antibump counter-  | Bump-  -- ^ Bump counter-  | Reset !Natural-  -- ^ Reset counter-  | HashCounter-  -- ^ Get counter's hash using void entry point (which implies that-  -- everything else should fail)-  | Add !Natural-  -- ^ Add a constant to caller-add-  | AddRecord-  -- ^ Add counter value to caller-add-  | Append !Natural-  -- ^ Append a constant to caller-append-  | AppendRecord-  -- ^ Append counter value to caller-append-  deriving (Show, Generic)--genAction :: Gen Action-genAction = genericArbitrary--data Fixture = Fixture-  { fActions :: ![Action]-  , fInitialCounter :: !Natural-  , fInitialList :: ![Natural]-  , fInitialSum :: !Natural-  } deriving (Show)---- We generate 'HashCounter' with smaller probablity, because otherwise--- tests will often stop quickly (they stop as soon as 'HashCounter'--- occurs).-genFixture :: Gen Fixture-genFixture = do-  fActions <--    listOf $ frequency-      [ (26, genAction `suchThat` notHashCounter)-      , (1, pure HashCounter)-      ]-  fInitialCounter <- arbitrary-  fInitialList <- arbitrary-  fInitialSum <- arbitrary-  pure Fixture {..}-  where-    notHashCounter =-      \case-        HashCounter -> False-        _ -> True--data ExpectedFail-  = NegativeCounter-  | HashCounterCalled !ByteString--expectedOutcome :: Fixture -> Either ExpectedFail Outcome-expectedOutcome Fixture {..} =-  runExcept $ execStateT (mapM_ step fActions) start-  where-    start = Outcome-      { _oCounter = fInitialCounter-      , _oList = fInitialList-      , _oSum = fInitialSum-      }-    step :: Action -> StateT Outcome (Except ExpectedFail) ()-    step = \case-      Antibump -> use oCounter >>= \case-        0 -> throwError NegativeCounter-        _ -> oCounter -= 1-      Bump -> oCounter += 1-      Reset x -> oCounter .= x-      HashCounter ->-        throwError .-        HashCounterCalled .-        sha512 .-        packValue' .-        T.toVal =<<-        use oCounter-      Add x -> oSum += x-      AddRecord -> (oSum +=) =<< use oCounter-      Append x -> oList %= (x:)-      AppendRecord -> do-        c <- use oCounter-        oList %= (c:)--specImpl ::-     (U.Contract, L.Contract CounterParameter CounterStorage)-  -> (U.Contract, L.Contract FeatherParameter FeatherStorage)-  -> (U.Contract, L.Contract CallerParameter CallerAddStorage)-  -> (U.Contract, L.Contract CallerParameter CallerAppendStorage)-  -> Spec-specImpl (_, counter) (_, feather) (_, callerAdd) (_, callerAppend) =-  prop "A mix of random actions is handled as expected" $-    forAll genFixture $ \fixture ->-      integrationalTestProperty (scenario fixture)-  where-    scenario :: Fixture -> IntegrationalScenario-    scenario fixture@Fixture {..} = do-      let-        initBalance = unsafeMkMutez 100--      counterContractAddress@(T.ContractAddr counterAddress) <--        lOriginate counter "counter" fInitialCounter initBalance--      let-        defaultFeatherValue :: FeatherStorage-        defaultFeatherValue =-          (counterAddress, Nothing @Address)--      featherContractAddress@(T.ContractAddr featherAddress) <--        lOriginate feather "feather" defaultFeatherValue initBalance-      cAddContractAddress <--        lOriginate callerAdd "caller-add"-        (fInitialSum, featherAddress) initBalance-      cAppendContractAddress <--        lOriginate callerAppend "caller-append"-        (fInitialList, featherAddress) initBalance--      let-        transfer' ::-          forall t . (T.IsoValue t, SingI (T.ToT t), T.HasNoOp (T.ToT t))-          => T.ContractAddr t -> t -> IntegrationalScenarioM ()-        transfer' addr param =-          lTransfer (#from .! genesisAddress) (#to .! addr)-                    (unsafeMkMutez 0) param--        transferToCounter :: CounterParameter -> IntegrationalScenarioM ()-        transferToCounter = transfer' counterContractAddress--        transferToAdd :: CallerParameter -> IntegrationalScenarioM ()-        transferToAdd = transfer' cAddContractAddress--        transferToAppend :: CallerParameter -> IntegrationalScenarioM ()-        transferToAppend = transfer' cAppendContractAddress--        performAction :: Action -> IntegrationalScenarioM ()-        performAction = \case-          Antibump -> transferToCounter AntibumpCounter-          Bump -> transferToCounter BumpCounter-          Reset x -> transferToCounter $ ResetCounter x-          HashCounter -> transferToCounter $ HashCount (L.mkVoid ())-          Add x -> transferToAdd $ Left x-          AddRecord -> transferToAdd $ Right ()-          Append x -> transferToAppend $ Left x-          AppendRecord -> transferToAppend $ Right ()--      mapM_ performAction fActions--      let-        checkHash :: ByteString -> MichelsonFailed -> Bool-        checkHash expectedHash = (== MichelsonFailedWith (T.toVal expectedHash))-        validator :: IntegrationalValidator-        validator = case expectedOutcome fixture of-          Left NegativeCounter ->-            Left $ expectMichelsonFailed (const True) counterAddress-          Left (HashCounterCalled expectedHash) ->-            Left $ expectMichelsonFailed (checkHash expectedHash) counterAddress-          Right (Outcome {..}) -> Right $ composeValidatorsList-            [ -- Feather must always be called twice and the second-              -- call must set its storage to its initial value.-              lExpectStorageConst featherContractAddress defaultFeatherValue-            , -- Counter, caller-add and caller-append have values-              -- according to 'Outcome'.-              lExpectStorageConst counterContractAddress _oCounter-            , lExpectStorageConst cAddContractAddress (_oSum, featherAddress)-            , lExpectStorageConst cAppendContractAddress (_oList, featherAddress)-            , -- Balances must not change-              expectBalance counterAddress initBalance-            , expectBalance featherAddress initBalance-            , lExpectBalance cAddContractAddress initBalance-            , lExpectBalance cAppendContractAddress initBalance-            ]--      validate validator
+ test/Test/Interpreter/Auction.hs view
@@ -0,0 +1,131 @@+-- | Module, containing spec to test auction.tz contract.+--+-- This spec is an example of using testing capabilities of morley.+module Test.Interpreter.Auction+  ( test_Auction+  ) where++import Test.Hspec.Expectations (shouldSatisfy)+import Test.QuickCheck (Property, arbitrary, choose, counterexample, (.&&.), (===))+import Test.QuickCheck.Property (forAll, withMaxSuccess)+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)+import Test.Tasty.QuickCheck (testProperty)++import Michelson.Interpret (ContractEnv(..))+import Michelson.Test+  (ContractPropValidator, contractProp, midTimestamp, testTreesWithTypedContract)+import Michelson.Test.Dummy+import Michelson.Test.Util (failedProp)+import Michelson.Typed (CValue(..), Operation'(..), ToT, TransferTokens(..))+import qualified Michelson.Typed as T+import Tezos.Address (Address(..))+import Tezos.Core (Mutez, Timestamp, timestampPlusSeconds, unMutez, unsafeMkMutez, unsafeSubMutez)+import Tezos.Crypto (KeyHash)+import Util.Test.Arbitrary (runGen)++type Storage = (Timestamp, (Mutez, KeyHash))+type Param = KeyHash++-- | Spec to test auction.tz contract.+--+-- This test serves as an example on how to test contract with both unit tests+-- and QuickCheck.+test_Auction :: IO [TestTree]+test_Auction =+  testTreesWithTypedContract "contracts/tezos_examples/attic/auction.tz" auctionTest+  where+    -- Test auction.tz, everything should be fine+    auctionTest contract =+      pure+      [ testCase "Bid after end of auction triggers failure" $+          contractProp contract+            (flip shouldSatisfy (isLeft . fst))+            (env { ceAmount = unsafeMkMutez 1200 })+            keyHash2+            (aBitBeforeMidTimestamp, (unsafeMkMutez 1000, keyHash1))++      , testProperty "Random check (sparse distribution)" $ withMaxSuccess 200 $+          qcProp contract arbitrary arbitrary++      , testProperty "Random check (dense end of auction)" $+          qcProp contract denseTime arbitrary++      , testProperty "Random check (dense amount)" $+          qcProp contract arbitrary denseAmount+      ]++    qcProp contract eoaGen amountGen =+      forAll ((,) <$> eoaGen <*> ((,) <$> amountGen <*> arbitrary)) $+        \s p ->+          let validate = validateAuction env p s+           in contractProp contract validate env p s++    aBitBeforeMidTimestamp = midTimestamp `timestampPlusSeconds` -1+    -- ^ 1s before NOW++    denseTime = timestampPlusSeconds midTimestamp <$> choose (-4, 4)+    denseAmount = unsafeMkMutez . (midAmount +) . fromInteger <$> choose (-4, 4)++    env = dummyContractEnv+            { ceNow = midTimestamp+            , ceAmount = unsafeMkMutez midAmount+            }+    midAmount = unMutez (maxBound `unsafeSubMutez` minBound) `div` 2++keyHash1 :: KeyHash+keyHash1 = runGen 300406 arbitrary++keyHash2 :: KeyHash+keyHash2 = runGen 142917 arbitrary++-- | This validator checks the result of auction.tz execution.+--+-- It checks following properties:+--+-- * Current timestamp is before end of auction+-- * Amount of new bid is higher than previous one+--+-- In case of successful execution:+--+-- * End of auction timestamp in updated storage is unchanged+-- * Amount in updated storage is equal to @AMOUNT@ of transaction+-- * Key hash in updated storage is equal to contract's parameter+-- * Script returned exactly one operation, @TransferTokens@, which+--   returns money back to the previous bidder+validateAuction+  :: ContractEnv+  -> Param+  -> Storage+  -> ContractPropValidator (ToT Storage) Property+validateAuction env newKeyHash (endOfAuction, (amount, keyHash)) (resE, _)+  | ceNow env > endOfAuction+      = counterexample "Failure didn't trigger on end of auction" $ isLeft resE+  | ceAmount env <= amount+      = counterexample ("Failure didn't trigger on attempt to bid"+                        <> " with amount <= than previous bid") $ isLeft resE+  | Left e <- resE+      = failedProp $ "Unexpected script fail: " <> show e++  | Right (_, (T.VPair ( T.VC (CvTimestamp endOfAuction'), _))) <- resE+  , endOfAuction /= endOfAuction'+      = failedProp "End of auction timestamp of contract changed"++  | Right (_, (T.VPair (_, T.VPair (T.VC (CvMutez amount'), _)))) <- resE+  , amount' /= ceAmount env+      = failedProp $ "Storage updated to wrong value: new amount"+                      <> " is not equal to amount of transaction"+  | Right (_, (T.VPair (_, T.VPair (_, T.VC (CvKeyHash keyHash'))))) <- resE+  , keyHash' /= newKeyHash+      = failedProp $ "Storage updated to wrong value: new key hash"+                      <> " is not equal to contract's parameter"++  | Right (ops, _) <- resE+     = let counterE msg =+              counterexample $ "Invalid money back operation (" <> msg <> ")"+        in case ops of+            [OpTransferTokens (TransferTokens T.VUnit retAmount (T.VContract retAddr _))] ->+              counterE "wrong amount" (retAmount === amount)+                .&&.+              counterE "wrong address" (KeyAddress keyHash === retAddr)+            _ -> failedProp $ "Unexpected operation list: " <> show ops
test/Test/Interpreter/CallSelf.hs view
@@ -1,16 +1,18 @@ -- | Tests for the contract that calls self several times.  module Test.Interpreter.CallSelf-  ( selfCallerSpec+  ( test_self_caller   ) where -import Test.Hspec (Expectation, Spec, it, parallel, shouldBe)-import Test.Hspec.QuickCheck (modifyMaxSuccess, prop)-import Test.QuickCheck (Gen, choose, forAll)+import Test.HUnit (Assertion, (@?=))+import Test.QuickCheck (Gen, choose, forAll, withMaxSuccess)+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)+import Test.Tasty.QuickCheck (testProperty)  import Michelson.Interpret (ContractEnv(..), InterpreterState(..), RemainingSteps(..)) import Michelson.Runtime.GState-import Michelson.Test (ContractPropValidator, contractProp, specWithContract)+import Michelson.Test (ContractPropValidator, contractProp, testTreesWithContract) import Michelson.Test.Dummy import Michelson.Test.Integrational import Michelson.Typed@@ -18,11 +20,10 @@ import Tezos.Address (Address) import Tezos.Core (unsafeMkMutez) -selfCallerSpec :: Spec-selfCallerSpec =-  parallel $-  specWithContract "contracts/call_self_several_times.tz" $ \selfCaller ->-  specImpl selfCaller+test_self_caller :: IO [TestTree]+test_self_caller =+  testTreesWithContract "contracts/call_self_several_times.tz" $ \selfCaller ->+  pure (testImpl selfCaller)  data Fixture = Fixture   { fMaxSteps :: RemainingSteps@@ -52,31 +53,33 @@ type Parameter = 'Tc 'CInt type Storage = 'Tc 'CNat -specImpl ::+testImpl ::      (U.Contract, Contract Parameter Storage)-  -> Spec-specImpl (uSelfCaller, selfCaller) = modifyMaxSuccess (min 10) $ do-  it ("With parameter 1 single execution consumes " <>+  -> [TestTree]+testImpl (uSelfCaller, selfCaller) =+  [ testCase ("With parameter 1 single execution consumes " <>       show @_ @Int gasForLastExecution <> " gas") $     contractProp selfCaller (unitValidator gasForLastExecution) unitContractEnv     (1 :: Integer) (0 :: Natural) -  it ("With parameter 2 single execution consumes " <>+  , testCase ("With parameter 2 single execution consumes " <>       show @_ @Int gasForOneExecution <> " gas") $     contractProp selfCaller (unitValidator gasForOneExecution) unitContractEnv     (2 :: Integer) (0 :: Natural) -  prop propertyDescription $+  , testProperty propertyDescription $+    withMaxSuccess 10 $     forAll genFixture $ \fixture ->       integrationalTestProperty (integrationalScenario uSelfCaller fixture)+  ]   where     -- Environment for unit test     unitContractEnv = dummyContractEnv     -- Validator for unit test     unitValidator ::-      RemainingSteps -> ContractPropValidator Storage Expectation+      RemainingSteps -> ContractPropValidator Storage Assertion     unitValidator gasDiff (_, isRemainingSteps -> remSteps) =-      remSteps `shouldBe` ceMaxSteps unitContractEnv - gasDiff+      remSteps @?= ceMaxSteps unitContractEnv - gasDiff      propertyDescription =       "calls itself as many times as you pass to it as a parameter, " <>
test/Test/Interpreter/Compare.hs view
@@ -1,15 +1,15 @@ -- | Module, containing spec to test compare.tz contract. module Test.Interpreter.Compare-  ( compareSpec+  ( test_compare   ) where -import Test.Hspec (Spec, it, parallel)-import Test.Hspec.QuickCheck (prop) import Test.QuickCheck (Property, (===)) import Test.QuickCheck.Property (withMaxSuccess)+import Test.Tasty (TestTree)+import Test.Tasty.QuickCheck (testProperty)  import Michelson.Interpret (InterpreterState, MichelsonFailed)-import Michelson.Test (contractProp, specWithTypedContract)+import Michelson.Test (contractProp, testTreesWithTypedContract) import Michelson.Test.Dummy import Michelson.Test.Util (failedProp) import Michelson.Typed (ToT, fromVal)@@ -23,19 +23,19 @@      , InterpreterState)  -- | Spec to test compare.tz contract.-compareSpec :: Spec-compareSpec = parallel $ do--  specWithTypedContract "contracts/tezos_examples/compare.tz" $ \contract -> do+test_compare :: IO [TestTree]+test_compare =+  testTreesWithTypedContract "contracts/tezos_examples/macros/compare.tz" $ \contract ->     let       contractProp' inputParam =         contractProp contract (validate (mkExpected inputParam))         dummyContractEnv inputParam initStorage--    it "success test" $-      contractProp' (unsafeMkMutez 10, unsafeMkMutez 11)--    prop "Random check" $ withMaxSuccess 200 contractProp'+    in pure+    [ testProperty "success test" $+        contractProp' (unsafeMkMutez 10, unsafeMkMutez 11)+    , testProperty "Random check" $+        withMaxSuccess 200 contractProp'+    ]   where     initStorage :: [Bool]     initStorage = []
test/Test/Interpreter/Conditionals.hs view
@@ -1,16 +1,16 @@ -- | Module, containing spec to test conditionals.tz contract. module Test.Interpreter.Conditionals-  ( conditionalsSpec+  ( test_conditionals   ) where -import Test.Hspec (Spec, it, parallel)-import Test.Hspec.QuickCheck (prop)+import Test.Tasty (TestTree)+import Test.Tasty.QuickCheck (testProperty) import Test.QuickCheck (Property, (===)) import Test.QuickCheck.Instances.Text () import Test.QuickCheck.Property (withMaxSuccess)  import Michelson.Interpret (InterpreterState, MichelsonFailed)-import Michelson.Test (contractProp, specWithTypedContract)+import Michelson.Test (contractProp, testTreesWithTypedContract) import Michelson.Test.Dummy (dummyContractEnv) import Michelson.Test.Util (failedProp, qcIsLeft, qcIsRight) import Michelson.Typed (CValue(..), ToT)@@ -24,19 +24,19 @@      , InterpreterState)  -- | Spec to test conditionals.tz contract.-conditionalsSpec :: Spec-conditionalsSpec = parallel $ do--  specWithTypedContract "contracts/tezos_examples/conditionals.tz" $ \contract -> do+test_conditionals :: IO [TestTree]+test_conditionals =+  testTreesWithTypedContract "contracts/tezos_examples/attic/conditionals.tz" $ \contract ->     let       contractProp' inputParam =         contractProp contract (validate inputParam) dummyContractEnv inputParam         [mt|storage|]--    it "success 1 test" $-      contractProp' $ Left [mt|abc|]--    prop "Random check" $ withMaxSuccess 200 contractProp'+    in pure+    [ testProperty "success 1 test" $+        contractProp' $ Left [mt|abc|]+    , testProperty "Random check" $+        withMaxSuccess 200 contractProp'+    ]   where     validate       :: Show x
test/Test/Interpreter/ContractOp.hs view
@@ -1,41 +1,41 @@ -- | Module, containing spec to test contract_op.tz contract. module Test.Interpreter.ContractOp-  ( contractOpSpec+  ( test_contract_op   ) where  import qualified Data.Map as M-import Test.Hspec (Spec, describe, it, parallel) import Test.QuickCheck (Property, (===))+import Test.Tasty (TestTree)+import Test.Tasty.QuickCheck (testProperty)  import Michelson.Interpret (ContractEnv(..), ContractReturn)-import Michelson.Test (contractProp, dummyContractEnv, failedProp, specWithTypedContract)+import Michelson.Test (contractProp, dummyContractEnv, failedProp, testTreesWithTypedContract) import Michelson.Typed (Contract, ToT, fromVal) import Michelson.Untyped (CT(..), T(..), Type(..), noAnn)-import Tezos.Address (Address, unsafeParseAddress)+import Tezos.Address  -- | Spec to test compare.tz contract.-contractOpSpec :: Spec-contractOpSpec = parallel $ describe "CONTRACT instruction tests" $ do-  specWithTypedContract "contracts/contract_op.tz" $ \contract -> do-    it "contract not found" $+test_contract_op :: IO [TestTree]+test_contract_op =+  testTreesWithTypedContract "contracts/contract_op.tz" $ \contract -> pure+  [ testProperty "contract not found" $       contractProp' False [] contract--    it "contract found, expected parameter is int :q, actual is int :q" $+  , testProperty "contract found, expected parameter is int :q, actual is int :q" $       contractProp' True [(addr, intQ)] contract-    it "contract found, expected parameter int :q, actual int" $+  , testProperty "contract found, expected parameter int :q, actual int" $       contractProp' True [(addr, int)] contract--    it "contract found, but expected parameter is int :p, actual is int :q" $+  , testProperty "contract found, but expected parameter is int :p, actual is int :q" $       contractProp' False [(addr, intP)] contract-    it "contract found, but expected parameter is int :p, actual is string" $+  , testProperty "contract found, but expected parameter is int :p, actual is string" $       contractProp' False [(addr, string)] contract+  ]   where     intQ = Type (Tc CInt) "q"     int = Type (Tc CInt) noAnn     intP = Type (Tc CInt) "p"     string = Type (Tc CString) noAnn -    addr = unsafeParseAddress "KT1WsLzQ61xtMNJHfwgCHh2RnALGgFAzeSx9"+    addr = unsafeParseContractHash "KT1WsLzQ61xtMNJHfwgCHh2RnALGgFAzeSx9"      validate       :: Bool@@ -45,11 +45,11 @@     validate _ (Left _, _) = failedProp "Unexpected fail in interepreter"     validate _ _ = failedProp "Unexpected result of script execution" -    contractProp' :: Bool -> [(Address, Type)] -> Contract (ToT Address) (ToT Bool) -> Property+    contractProp' :: Bool -> [(ContractHash, Type)] -> Contract (ToT Address) (ToT Bool) -> Property     contractProp' res ctrs contract =       contractProp         contract         (validate res)         dummyContractEnv {ceContracts = M.fromList ctrs}-        addr+        (ContractAddress addr)         False
test/Test/Interpreter/EnvironmentSpec.hs view
@@ -1,27 +1,31 @@ -- | Tests for the 'environment.tz' contract  module Test.Interpreter.EnvironmentSpec-  ( environmentSpec+  ( test_environment   ) where -import Test.Hspec (Spec)-import Test.Hspec.QuickCheck (modifyMaxSuccess, prop)-import Test.QuickCheck (Arbitrary(..), choose)+import Test.QuickCheck (Arbitrary(..), choose, withMaxSuccess) import Test.QuickCheck.Instances.Text ()+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)+import Test.Tasty.QuickCheck (testProperty)  import Michelson.Interpret (RemainingSteps(..)) import Michelson.Runtime.GState-import Michelson.Test (specWithContract)+import Michelson.Test (testTreesWithContract) import Michelson.Test.Integrational import Michelson.Typed import qualified Michelson.Typed as T import qualified Michelson.Untyped as U import Tezos.Address import Tezos.Core+import Tezos.Crypto (detSecretKey, toPublic) -environmentSpec :: Spec-environmentSpec =-  specWithContract "contracts/environment.tz" specImpl+test_environment :: IO [TestTree]+test_environment =+  testTreesWithContract "contracts/environment.tz" $ \contract ->+  pure [ testImpl contract+       , testCase ("Default balance") $ integrationalTestExpectation testDefaultBalance ]  data Fixture = Fixture   { fNow :: !Timestamp@@ -33,7 +37,7 @@  instance Arbitrary Fixture where   arbitrary = do-    fNow <- timestampFromSeconds @Int <$> choose (100000, 111111)+    fNow <- timestampFromSeconds <$> choose (100000, 111111)     fMaxSteps <- RemainingSteps <$> choose (1015, 1028)     fPassOriginatedAddress <- arbitrary     fBalance <- unsafeMkMutez <$> choose (1, 1234)@@ -44,7 +48,7 @@ shouldExpectFailed fixture =   or     [ fBalance fixture > unsafeMkMutez 1000-    , fNow fixture < timestampFromSeconds @Int 100500+    , fNow fixture < timestampFromSeconds 100500     , fPassOriginatedAddress fixture     , fAmount fixture < unsafeMkMutez 15     ]@@ -56,15 +60,15 @@   where     consumedGas = 19 -specImpl ::+testImpl ::     (U.Contract, T.Contract ('Tc 'CAddress) ('Tc 'CBool))-  -> Spec-specImpl (uEnvironment, _environment)  = do-  let scenario = integrationalScenario uEnvironment-  modifyMaxSuccess (min 50) $-    prop description $-      integrationalTestExpectation . scenario+  -> TestTree+testImpl (uEnvironment, _environment)  = do+  testProperty description $+    withMaxSuccess 50 $+      integrationalTestProperty . scenario   where+    scenario = integrationalScenario uEnvironment     description =       "This contract fails under conditions described in a comment at the " <>       "beginning of this contract and returns whether remaining gas is " <>@@ -102,3 +106,9 @@       | otherwise =         Right $ expectStorageConst environmentAddress $ shouldReturn fixture   validate validator++testDefaultBalance :: IntegrationalScenario+testDefaultBalance = do+  let genKey seed = mkKeyAddress . toPublic . detSecretKey $ seed+      addr = genKey "random address testDefaultBalance"+  validate . Right $ expectBalance addr (unsafeMkMutez 0)
test/Test/Interpreter/StringCaller.hs view
@@ -3,48 +3,50 @@ -- their behavior.  module Test.Interpreter.StringCaller-  ( stringCallerSpec+  ( test_stringCaller   ) where -import Test.Hspec (Spec, it, parallel)-import Test.Hspec.QuickCheck (modifyMaxSuccess, prop)+import Test.QuickCheck (withMaxSuccess) import Test.QuickCheck.Instances.Text ()+import Test.Tasty (TestTree)+import Test.Tasty.QuickCheck (testProperty)+import Test.Tasty.HUnit (testCase)  import Michelson.Runtime.GState-import Michelson.Test (specWithContract)+import Michelson.Test (testTreesWithContract) import Michelson.Test.Integrational-import Michelson.Typed import Michelson.Text+import Michelson.Typed import qualified Michelson.Typed as T import qualified Michelson.Untyped as U import Tezos.Address import Tezos.Core -stringCallerSpec :: Spec-stringCallerSpec =-  parallel $-  specWithContract "contracts/string_caller.tz" $ \stringCaller ->-  specWithContract "contracts/fail_or_store_and_transfer.tz" $ \failOrStoreAndTransfer ->-  specImpl stringCaller failOrStoreAndTransfer+test_stringCaller :: IO [TestTree]+test_stringCaller =+  testTreesWithContract "contracts/string_caller.tz" $ \stringCaller ->+  testTreesWithContract "contracts/fail_or_store_and_transfer.tz" $ \failOrStoreAndTransfer ->+  pure $ testImpl stringCaller failOrStoreAndTransfer -specImpl ::+testImpl ::      (U.Contract, T.Contract ('Tc 'CString) ('Tc 'CAddress))   -> (U.Contract, T.Contract ('Tc 'CString) ('Tc 'CString))-  -> Spec-specImpl (uStringCaller, _stringCaller) (uFailOrStore, _failOrStoreAndTransfer) = do+  -> [TestTree]+testImpl (uStringCaller, _stringCaller) (uFailOrStore, _failOrStoreAndTransfer) =   let scenario = integrationalScenario uStringCaller uFailOrStore-  let prefix =+      prefix =         "stringCaller calls failOrStoreAndTransfer and updates its storage with "-  let suffix =+      suffix =         " and properly updates balances. But fails if failOrStoreAndTransfer's"         <> " balance is ≥ 1000 and NOW is ≥ 500"-  it (prefix <> "a constant" <> suffix) $+  in+  [ testCase (prefix <> "a constant" <> suffix) $     integrationalTestExpectation (scenario constStr)-   -- The test is trivial, so it's kinda useless to run it many times-  modifyMaxSuccess (const 2) $-    prop (prefix <> "an arbitrary value" <> suffix) $+  , testProperty (prefix <> "an arbitrary value" <> suffix) $+    withMaxSuccess 2 $       \str -> integrationalTestProperty (scenario str)+  ]   where     constStr = [mt|caller|] @@ -63,7 +65,7 @@     initStringCallerBalance    -- NOW = 500, so stringCaller shouldn't fail-  setNow (timestampFromSeconds @Int 500)+  setNow (timestampFromSeconds 500)    -- Transfer 100 tokens to stringCaller, it should transfer 300 tokens   -- to failOrStoreAndTransfer@@ -135,7 +137,7 @@   void $ validate (Right expectAnySuccess)    -- Now let's set NOW to 600 and expect stringCaller to fail-  setNow (timestampFromSeconds @Int 600)+  setNow (timestampFromSeconds 600)   transferToStringCaller   validate (Left $ expectMichelsonFailed (const True) stringCallerAddress) 
+ test/Test/Lorentz/Base.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}++-- | Tests for basic Lorentz functionality.++module Test.Lorentz.Base+  ( unit_parseLorentzValue+  ) where++import Test.HUnit (Assertion, (@?=))++import Lorentz.Base (parseLorentzValue)+import Michelson.Typed (IsoValue)++-- Sum type.+data S+  = S1 Bool+  | S2+  | S3 Integer+  deriving stock (Generic, Eq, Show)+  deriving anyclass (IsoValue)++-- Product type.+type P = (Bool, Integer, S, S)++unit_parseLorentzValue :: Assertion+unit_parseLorentzValue = do+  parseLorentzValue "Left True" @?= Right (S1 True)+  parseLorentzValue @P "Pair (Pair False 20) (Pair (Right (Left Unit)) (Right (Right 15)))" @?=+    Right (False, 20, S2, S3 15)
+ test/Test/Lorentz/DeadCode.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE DeriveAnyClass, DerivingStrategies #-}++-- | Tests checking dead code avoidance in Lorentz.++module Test.Lorentz.DeadCode+  ( test_Test+  ) where++import Control.Spoon (spoon)+import Test.HUnit (assertBool, (@?=))+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)++import qualified Lorentz as L+import Lorentz.Base+import Lorentz.Run+import Michelson.Typed (Instr(Seq))+import qualified Michelson.Typed as T++test_Test :: [TestTree]+test_Test =+  [ testCase "Can construct normal instructions" $+      L.push @Integer 5 # L.drop+        `compilesTo` (T.PUSH (T.toVal @Integer 5) `Seq` T.DROP)++  , testCase "Dead code is cut off" $+      (L.unit # L.failWith) # L.drop+        `compilesTo` (T.UNIT `Seq` T.FAILWITH)++  , testCase "Dead code after all failing if branches is cut off" $+      (L.push True # L.if_ L.failWith L.failWith) # L.drop+        `compilesTo` (T.PUSH (T.toVal True) `Seq` T.IF T.FAILWITH T.FAILWITH)++  , testCase "Always failing DIP body is error" $+      L.dip (L.unit # L.failWith)+        & fails+  ]+  where+    compilesTo linstr instr =+      compileLorentz @'[()] linstr @?= instr+    infixr 0 `compilesTo`++    fails instr =+      assertBool "instruction construction didn't fail" . isNothing . spoon $+      compileLorentz instr
− test/Test/Lorentz/Discovery.hs
@@ -1,114 +0,0 @@-{-# LANGUAGE QuasiQuotes #-}---- | Tests for contracts discovery.--module Test.Lorentz.Discovery-  ( test_Export_list_parse-  , test_Haskell_modules_detection-  ) where--import Test.HUnit (assertFailure, (@?=))-import Test.Tasty (TestTree)-import Test.Tasty.HUnit (testCase)-import Text.InterpolatedString.QM (qnb)-import Text.Megaparsec (errorBundlePretty, runParser)--import Lorentz.Discover--test_Export_list_parse :: [TestTree]-test_Export_list_parse =-  [ testCase "Empty" $-    [qnb| module MyModule () where-        |] `shouldParseTo` []--  , testCase "Empty spaced" $-    [qnb| module MyModule (  ) where-        |] `shouldParseTo` []--  , testCase "Contracts extracted fine" $-      [qnb| module MyModule-              ( contract_Some-              , contract_one_another-              ) where-      |]-      `shouldParseTo`-       [ ExportedContractInfo-         { eciModuleName = "MyModule"-         , eciContractDecl = ExportedContractDecl-           { ecdName = "Some"-           , ecdVar = "contract_Some"-           }-         }-       , ExportedContractInfo-         { eciModuleName = "MyModule"-         , eciContractDecl = ExportedContractDecl-           { ecdName = "one another"-           , ecdVar = "contract_one_another"-           }-         }-       ]--  , testCase "Bad export entries are ignored" $-      [qnb| module MyModule-              ( not_a_contract-              , SomeType (..)-              , SomethingElse ( Ctor, getter )-              , SomethingElse2-                 ( Ctor2  -- constructor-                 , getter2  {- getter -})-              , contract-              , contract_Some-              ) where-      |]-      `shouldParseTo`-       [ ExportedContractInfo-         { eciModuleName = "MyModule"-         , eciContractDecl = ExportedContractDecl-           { ecdName = "Some"-           , ecdVar = "contract_Some"-           }-         }-       ]--  , testCase "Annotations and comments" $-      [qnb| {-# PRAGMA #-}-            -- Comment-            -- | Description-            {- Another comment-            -}-            module MyModule-              ( contract_Some  -- Should be exported--                -- ** And these should not-              , contract-              ) where-      |]-      `shouldParseTo`-       [ ExportedContractInfo-         { eciModuleName = "MyModule"-         , eciContractDecl = ExportedContractDecl-           { ecdName = "Some"-           , ecdVar = "contract_Some"-           }-         }-       ]--  ]-  where-    shouldParseTo code exports =-      case runParser haskellExportsParser "" code of-        Left err -> assertFailure $ errorBundlePretty err-        Right x -> x @?= exports---test_Haskell_modules_detection :: [TestTree]-test_Haskell_modules_detection =-  [ testCase "Simple module is picked" $-      isHaskellModule "Module.hs" @?= True-  , testCase "Not .hs module is ignored" $-      isHaskellModule "Module" @?= False-  , testCase "Modules with non letters are picked" $-      isHaskellModule "Module_12.hs" @?= True-  , testCase "Emacs' temporal files should be ignored" $-      isHaskellModule ".#Module.hs" @?= False-  ]
+ test/Test/Lorentz/EntryPoints.hs view
@@ -0,0 +1,291 @@+{-# LANGUAGE DeriveAnyClass #-}++-- | Tests for Lorentz compilation which uses 'LorentzCompilationWay'.+module Test.Lorentz.EntryPoints+  ( test_FieldAnnotations+  , test_TypeAnnotations+  ) where++import Test.HUnit ((@?=))+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (testCase)++import Lorentz ((:!))+import qualified Lorentz as L+import Lorentz.EntryPoints+import Lorentz.Run+import Michelson.Typed+import Michelson.Untyped (FieldAnn, TypeAnn, ann, noAnn)++data MyEntryPoints1+  = Do1 Integer+  | Do2 (Integer, Integer)+  | Do3 MyEntryPoints2+  | Do4 MyParams+  deriving stock Generic+  deriving anyclass IsoValue++data MyEntryPoints2+  = Do10+  | Do11 Natural+  deriving stock Generic+  deriving anyclass IsoValue++data MyEntryPoints3+  = Do12 ("tuplearg" :! ("TL" :! Integer, "TR" :!  Natural), "boolarg" :! Bool)+  | Do13 ("integerarg" :! Integer, "boolarg" :! Bool)+  deriving stock Generic+  deriving anyclass IsoValue++data MyEntryPoints4+  = Do14 ("viewarg1" :! L.View ("owner" :! L.Address) Natural)+  | Do15 ()+  deriving stock Generic+  deriving anyclass IsoValue++data MyEntryPoints5+  = Do16 ("maybearg" :! Maybe ("maybeinner" :! Natural))+  | Do17 ()+  deriving stock Generic+  deriving anyclass IsoValue++data MyEntryPoints6+  = Do18 ("lambdaarg" :! L.Lambda Natural Natural)+  | Do19 ()+  deriving stock Generic+  deriving anyclass IsoValue++data MyEntryPoints7+  = Do20 ("listarg" :! [("balance" :! Natural , "address" :! L.Address)])+  | Do21 ()+  deriving stock Generic+  deriving anyclass IsoValue++data MyEntryPoints8+  = Do22 ("maparg" :! (Map Natural ("balance" :! Natural , "address" :! L.Address)))+  | Do23 ()+  deriving stock Generic+  deriving anyclass IsoValue++data MyEntryPoints9+  = Do24 ("maybearg" L.:? ("maybeinner" :! Natural))+  | Do25 ()+  deriving stock Generic+  deriving anyclass IsoValue++data MyEntryPoints10+  = Do26 ("bigmaparg" :! L.Lambda (BigMap Natural ("balance" :! Natural , "address" :! L.Address)) ())+  | Do27 ()+  deriving stock Generic+  deriving anyclass IsoValue++data MyParams = MyParams+  { param1 :: ()+  , param2 :: ByteString+  }+  deriving stock Generic+  deriving anyclass IsoValue++instance ParameterEntryPoints MyEntryPoints1 where+  parameterEntryPoints = pepRecursive++newtype MyEntryPoints1' = MyEntryPoints1' MyEntryPoints1+  deriving newtype IsoValue++instance ParameterEntryPoints MyEntryPoints1' where+  parameterEntryPoints = mapParameterEntryPoints MyEntryPoints1' pepPlain++instance ParameterEntryPoints MyEntryPoints2 where+  parameterEntryPoints = pepPlain++instance ParameterEntryPoints MyEntryPoints3 where+  parameterEntryPoints = pepPlain++instance ParameterEntryPoints MyEntryPoints4 where+  parameterEntryPoints = pepPlain++instance ParameterEntryPoints MyEntryPoints5 where+  parameterEntryPoints = pepPlain++instance ParameterEntryPoints MyEntryPoints6 where+  parameterEntryPoints = pepPlain++instance ParameterEntryPoints MyEntryPoints7 where+  parameterEntryPoints = pepPlain++instance ParameterEntryPoints MyEntryPoints8 where+  parameterEntryPoints = pepPlain++instance ParameterEntryPoints MyEntryPoints9 where+  parameterEntryPoints = pepPlain++instance ParameterEntryPoints MyEntryPoints10 where+  parameterEntryPoints = pepPlain++contract1 :: L.Contract MyEntryPoints1 ()+contract1 = L.drop L.# L.unit L.# L.nil L.# L.pair++contract1' :: L.Contract MyEntryPoints1' ()+contract1' = L.drop L.# L.unit L.# L.nil L.# L.pair++contract2 :: L.Contract MyEntryPoints2 ()+contract2 = L.drop L.# L.unit L.# L.nil L.# L.pair++contract3 :: L.Contract MyEntryPoints3 ()+contract3 = L.drop L.# L.unit L.# L.nil L.# L.pair++contract4 :: L.Contract MyEntryPoints4 ()+contract4 = L.drop L.# L.unit L.# L.nil L.# L.pair++contract5 :: L.Contract MyEntryPoints5 ()+contract5 = L.drop L.# L.unit L.# L.nil L.# L.pair++contract6 :: L.Contract MyEntryPoints6 ()+contract6 = L.drop L.# L.unit L.# L.nil L.# L.pair++contract7 :: L.Contract MyEntryPoints7 ()+contract7 = L.drop L.# L.unit L.# L.nil L.# L.pair++contract8 :: L.Contract MyEntryPoints8 ()+contract8 = L.drop L.# L.unit L.# L.nil L.# L.pair++contract9 :: L.Contract MyEntryPoints9 ()+contract9 = L.drop L.# L.unit L.# L.nil L.# L.pair++contract10 :: L.Contract MyEntryPoints10 ()+contract10 = L.drop L.# L.unit L.# L.nil L.# L.pair++-- | Helper datatype which contains field annotations from 'NTOr'.+data FieldAnnTree t where+  Leaf :: FieldAnnTree t+  Node :: FieldAnn -> FieldAnnTree a+       -> FieldAnn -> FieldAnnTree b+       -> FieldAnnTree ('TOr a b)++deriving instance Eq (FieldAnnTree t)+deriving instance Show (FieldAnnTree t)++data TypeAnnTree t where+  TALeaf :: TypeAnn -> TypeAnnTree t+  TANodeOption :: TypeAnn -> TypeAnnTree a -> TypeAnnTree ('TOption a)+  TANodePair :: TypeAnn -> TypeAnnTree a -> TypeAnnTree b -> TypeAnnTree ('TPair a b)+  TANodeOr :: TypeAnn -> TypeAnnTree a -> TypeAnnTree b -> TypeAnnTree ('TOr a b)+  TANodeLambda :: TypeAnn -> TypeAnnTree a -> TypeAnnTree b -> TypeAnnTree ('TLambda a b)+  TANodeList :: TypeAnn -> TypeAnnTree a -> TypeAnnTree ('TList a)+  TANodeMap :: TypeAnn -> TypeAnnTree b -> TypeAnnTree ('TMap a b)+  TANodeBigMap :: TypeAnn -> TypeAnnTree b -> TypeAnnTree ('TBigMap a b)++deriving instance Eq (TypeAnnTree t)+deriving instance Show (TypeAnnTree t)++extractTypeAnnTres :: Notes t -> TypeAnnTree t+extractTypeAnnTres = \case+  NTc ta -> TALeaf ta+  NTKey ta -> TALeaf ta+  NTUnit ta -> TALeaf ta+  NTSignature ta -> TALeaf ta+  NTOption ta n1 -> TANodeOption ta (extractTypeAnnTres n1)+  NTList ta n1 -> TANodeList ta (extractTypeAnnTres n1)+  NTSet ta _ -> TALeaf ta+  NTOperation ta -> TALeaf ta+  NTContract ta _ -> TALeaf ta+  NTPair ta _ _ n1 n2 -> TANodePair ta (extractTypeAnnTres n1) (extractTypeAnnTres n2)+  NTOr ta _ _ n1 n2 -> TANodeOr ta (extractTypeAnnTres n1) (extractTypeAnnTres n2)+  NTLambda ta n1 n2 -> TANodeLambda ta (extractTypeAnnTres n1) (extractTypeAnnTres n2)+  NTMap ta _ n1 -> TANodeMap ta (extractTypeAnnTres n1)+  NTBigMap ta _ n1 -> TANodeBigMap ta (extractTypeAnnTres n1)+  NTChainId ta -> TALeaf ta++extractFieldAnnTree :: Notes t -> FieldAnnTree t+extractFieldAnnTree = \case+  NTOr _ lann rann lnotes rnotes ->+    Node lann (extractFieldAnnTree lnotes) rann (extractFieldAnnTree rnotes)+  _ ->+    Leaf++test_FieldAnnotations :: [TestTree]+test_FieldAnnotations =+  [ testCase "Simple parameter" $+      (paramAnnTree $ compileLorentzContract contract2)+      @?=+      Node+        (ann "do10") Leaf+        (ann "do11") Leaf++  , testGroup "Complex parameter"+    [ testCase "Interpreting as direct list of entrypoints" $+        (paramAnnTree $ compileLorentzContract contract1')+        @?=+        Node+          noAnn (Node (ann "do1") Leaf (ann "do2") Leaf)+          noAnn (Node (ann "do3") (Node noAnn Leaf noAnn Leaf) (ann "do4") Leaf)++    , testCase "Recursive entrypoints traversal" $+        (paramAnnTree $ compileLorentzContract contract1)+        @?=+        Node+          noAnn (Node (ann "do1") Leaf (ann "do2") Leaf)+          noAnn (Node+                  noAnn (Node (ann "do10") Leaf (ann "do11") Leaf)+                  (ann "do4") Leaf+                )+    ]+  ]+  where+    paramAnnTree :: FullContract cp st -> FieldAnnTree cp+    paramAnnTree = extractFieldAnnTree . fcParamNotes++test_TypeAnnotations :: [TestTree]+test_TypeAnnotations =+  [ testCase "Named field parameter" $+      (paramAnnTree $ compileLorentzContract contract3)+      @?=+      (TANodeOr noAnn+       (TANodePair noAnn (TANodePair (ann "tuplearg") (TALeaf (ann "TL")) (TALeaf (ann "TR"))) (TALeaf (ann "boolarg")))+       (TANodePair noAnn (TALeaf (ann "integerarg")) (TALeaf (ann "boolarg")))+      )+  , testCase "Named field parameter for views" $+      (paramAnnTree $ compileLorentzContract contract4)+      @?=+      (TANodeOr noAnn+        (TANodePair (ann "viewarg1") (TALeaf (ann "owner")) (TALeaf noAnn)) (TALeaf noAnn))++  , testCase "Maybe field parameter" $+      (paramAnnTree $ compileLorentzContract contract5)+      @?=+      (TANodeOr noAnn+        (TANodeOption (ann "maybearg") (TALeaf (ann "maybeinner"))) (TALeaf noAnn))++  , testCase "Lambda field parameter" $+      (paramAnnTree $ compileLorentzContract contract6)+      @?=+      (TANodeOr noAnn+        (TANodeLambda (ann "lambdaarg") (TALeaf noAnn) (TALeaf noAnn)) (TALeaf noAnn))++  , testCase "List field parameter" $+      (paramAnnTree $ compileLorentzContract contract7)+      @?=+      (TANodeOr noAnn+       (TANodeList (ann "listarg") (TANodePair noAnn (TALeaf (ann "balance")) (TALeaf (ann "address")))) (TALeaf noAnn))++  , testCase "Map field parameter" $+      (paramAnnTree $ compileLorentzContract contract8)+      @?=+      (TANodeOr noAnn+       (TANodeMap (ann "maparg") (TANodePair noAnn (TALeaf (ann "balance")) (TALeaf (ann "address")))) (TALeaf noAnn))++  , testCase "Maybe field parameter 2" $+      (paramAnnTree $ compileLorentzContract contract9)+      @?=+      (TANodeOr noAnn+        (TANodeOption (ann "maybearg") (TALeaf (ann "maybeinner"))) (TALeaf noAnn))++  , testCase "Big map field parameter" $+      (paramAnnTree $ compileLorentzContract contract10)+      @?=+      (TANodeOr noAnn+        (TANodeLambda (ann "bigmaparg") (TANodeBigMap noAnn (TANodePair noAnn (TALeaf (ann "balance")) (TALeaf (ann "address")))) (TALeaf noAnn)) (TALeaf noAnn))+  ]+  where+    paramAnnTree :: FullContract cp st -> TypeAnnTree cp+    paramAnnTree = extractTypeAnnTres . fcParamNotes
+ test/Test/Lorentz/Errors.hs view
@@ -0,0 +1,140 @@+{-# OPTIONS_GHC -Wno-deprecations #-}+{-# OPTIONS_GHC -Wno-orphans #-}++module Test.Lorentz.Errors+  ( unit_Errors+  , unit_gatherErrorTags+  , unit_Numeric_simple+  , unit_Numeric_append+  , unit_errorFromValNumeric+  ) where++import qualified Data.Bimap as Bimap+import qualified Data.HashSet as HS+import Test.HUnit (Assertion, (@?=))++import Lorentz as L+import Lorentz.Test.Integrational+import Michelson.Text (mt)++{- Checking that errors of old format still can be used fine -}++data ErrorOfOldFormat+  = ErrorCase1+  | ErrorCase2 Integer+  deriving stock Generic++deriveCustomError ''ErrorOfOldFormat++_canFailUsing :: s :-> s'+_canFailUsing = failUsing ErrorCase1++_canFailUsingArg :: Integer : s :-> s'+_canFailUsingArg = failUsingArg @ErrorOfOldFormat #cErrorCase2++-- Needed to make this module compile+unit_Errors :: IO ()+unit_Errors = pass++----------------------------------------------------------------------------+-- Numeric representation+----------------------------------------------------------------------------++unit_gatherErrorTags :: Assertion+unit_gatherErrorTags = sampleGatheredTags @?= HS.fromList [str1, str2]++unit_Numeric_simple :: Assertion+unit_Numeric_simple =+  useNumericErrors sample @?=+  (sampleNumericErrors (0, 1), Bimap.fromList [(0, str1), (1, str2)])++unit_Numeric_append :: Assertion+unit_Numeric_append =+  applyErrorTagMap newMap sample @?=+  sampleNumericErrors (5, 4)+  where+    existingMap :: ErrorTagMap+    existingMap = Bimap.fromList [(4, str2)]++    newMap = existingMap `addNewErrorTags` sampleGatheredTags++type instance ErrorArg "aa" = Bool+instance CustomErrorHasDoc "aa" where+  customErrClass = ErrClassActionException+  customErrDocMdCause = "patak"++sample :: '[ MText] :-> '[ MText]+sample =+  pushTrue #+  -- FailWithString+  if_+    (push str1 # failWith)+    pushTrue #+  -- Non-typical fail+  if_+    (push str1 # push str1 # pair # pair # failWith)+    pushTrue #+  -- FailWithStackValue+  if_+    (push str1 # pair # failWith)+    (pushTrue) #+  -- FailWithStackValue via 'failCustom'+  if_+    (pushTrue # failCustom #aa)+    (none @()) #+  -- Deeper FailWithString+  ifNone+    (unit # pushTrue # if_ (push str2 # failWith) nop)+    nop #+  -- FailWithConstantPair+  push (str2, ()) # failWith++-- Arguments are numeric codes for 'str1' and 'str2'.+sampleNumericErrors :: (Natural, Natural) -> '[ MText] :-> '[ MText]+sampleNumericErrors (code1, code2) =+  pushTrue #+  if_+    (push code1 # failWith)+    pushTrue #++  if_+    (push str1 # push str1 # pair # pair # failWith)+    pushTrue #++  if_+    (push code1 # pair # failWith)+    pushTrue #++  -- Here we lose doc item and rely on the fact that instructions are+  -- compared by transpiling them to Michelson.+  if_+    (pushTrue # push code1 # pair # failWith)+    (none @()) #++  ifNone+    (unit # pushTrue # if_ (push code2 # failWith) nop)+    nop #++  push (code2, ()) # failWith++sampleGatheredTags :: HashSet MText+sampleGatheredTags = gatherErrorTags sample++pushTrue :: forall s. s :-> Bool ': s+pushTrue = push True++str1, str2 :: MText+str1 = [mt|Aa|]+str2 = [mt|Qq|]++unit_errorFromValNumeric :: Assertion+unit_errorFromValNumeric = integrationalTestExpectation $ do+  let+    (voidSample', errorTagMap) = useNumericErrors voidSample+  ref <- lOriginate voidSample' "voidSample" () minBound+  lCall ref (mkVoid True)+  validate . Left $+    lExpectErrorNumeric errorTagMap (== VoidResult False)++voidSample :: Contract (Void_ Bool Bool) ()+voidSample = car # void_ L.not
+ test/Test/Lorentz/Extensible.hs view
@@ -0,0 +1,71 @@+module Test.Lorentz.Extensible+  ( test_Extensible+  ) where++import Data.Vinyl.Core (Rec(..))+import Test.HUnit ((@?=))+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)++import Lorentz (toVal)+import Lorentz.Base+import Lorentz.Extensible+import Lorentz.Run+import Michelson.Interpret.Pack+import Michelson.Test.Dummy++data SumType+  = Ctor0 Natural+  | Ctor1+  | Ctor2 (Integer, Integer)+  deriving stock (Generic, Eq, Show)++values :: [SumType]+values =+  [ Ctor0 42+  , Ctor1+  , Ctor2 (-100, 500)+  ]++test_Extensible :: [TestTree]+test_Extensible =+  [ testCase "toExtVal conversion" $ do+      fmap toExtVal values @?=+        [ Extensible (0, packValue' $ toVal @Natural 42)+        , Extensible (1, packValue' $ toVal ())+        , Extensible (2, packValue' $ toVal ints)+        ]+  , testCase "fromExtVal conversion" $ do+      let extValues = [ Extensible (0, packValue' $ toVal @Natural 42)+                      , Extensible (1, packValue' $ toVal ())+                      , Extensible (2, packValue' $ toVal ints)+                      ]+      fmap fromExtVal extValues @?= fmap Right values+  , testCase "fromExtVal failure" $ do+      let invalidCtor = Extensible (3, packValue' $ toVal ())+      let invalidArg = Extensible (2, packValue' $ toVal ())+      fromExtVal @SumType invalidCtor+        @?= Left (ConstructorIndexNotFound 3)+      fromExtVal @SumType invalidArg+        @?= Left ArgumentUnpackFailed+  , testCase "wrapExt" $ do+      wrapIntoCtor2 ints @?= (Right $ Extensible (2, packValue' $ toVal ints))+  , testCase "Roundtrip" $ do+      fmap roundtrip values @?= fmap Right values+  ]+  where+    wrapIntoCtor2 initVal = do+      let initStack = (Identity initVal :& RNil)+      resStack <- interpretLorentzInstr dummyContractEnv wrapCode initStack+      let Identity res :& RNil = resStack+      return res++ints :: (Integer, Integer)+ints = (-100, 500)++wrapCode :: '[(Integer, Integer)] :-> '[Extensible SumType]+wrapCode = wrapExt #cCtor2++roundtrip :: (ExtVal value) => value -> Either ExtConversionError value+roundtrip value =+  fromExtVal $ toExtVal value
test/Test/Lorentz/Macro.hs view
@@ -5,28 +5,41 @@ -- type-level numbers)  module Test.Lorentz.Macro-  ( unit_dropX-  , unit_elevateX+  ( unit_duupX+  , test_execute   ) where  import Prelude hiding (drop, swap) import Test.HUnit (Assertion, (@?=))+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)  import Lorentz -unit_dropX :: Assertion-unit_dropX = do-  dropX @0 @?= drop-  dropX @2 @?= dropX2-  where-    dropX2 :: [Integer, Bool, (), Bool] :-> [Integer, Bool, Bool]-    dropX2 = dip $ dip drop+import Michelson.Test.Dummy -unit_elevateX :: Assertion-unit_elevateX = do-  elevateX @0 @?= (dup # dip drop) -- current implementation is not efficient-  elevateX @1 @?= (dip dup # swap # dip (dip drop))-  elevateX @3 @?= elevateX3+unit_duupX :: Assertion+unit_duupX = do+  duupX @1 @?= dup+  duupX @2 @?= (dip dup # swap)+  duupX @3 @?= duupX3   where-    elevateX3 :: [Bool, Integer, Natural, (), Bool] :-> [(), Bool, Integer, Natural, Bool]-    elevateX3 = duupX @4 # dropX @4+    duupX3 :: [Bool, Integer, (), Bool] :-> [(), Bool, Integer, (), Bool]+    duupX3 = dipN @2 dup # dig @2++test_execute :: [TestTree]+test_execute =+  [ testCase "Two arguments lambda" $+      let lam :: [Integer, Integer] :-> [(), Integer]+          lam = add # unit+          code = push 3 # push lam # execute # drop @()+      in interpretLorentzLambda dummyContractEnv code 5+          @?= Right 8++  , testCase "Zero arguments lambda" $+      let lam :: '[] :-> '[Integer]+          lam = push 5+          code = drop # push lam # execute+      in interpretLorentzLambda dummyContractEnv code (0 :: Integer)+          @?= Right 5+  ]
+ test/Test/Lorentz/Print.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE DeriveAnyClass #-}++-- | Tests on Lorentz contracts pretty-printing.+module Test.Lorentz.Print+  ( test_Print_parameter_annotations+  ) where++import Test.HUnit ((@?=))+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)++import qualified Lorentz as L+import Lorentz.EntryPoints+import Lorentz.Run+import Michelson.Printer.Util (buildRenderDoc)+import Michelson.Typed+import Michelson.Untyped (para)++data MyEntryPoints1+  = Do1 Integer+  | Do2 (Integer, Integer)+  | Do3+  deriving stock Generic+  deriving anyclass IsoValue++instance ParameterEntryPoints MyEntryPoints1 where+  parameterEntryPoints = pepPlain++contract :: L.Contract MyEntryPoints1 ()+contract = L.drop L.# L.unit L.# L.nil L.# L.pair++test_Print_parameter_annotations :: [TestTree]+test_Print_parameter_annotations =+  [ testCase "Simple parameter" $+      let typedContract = compileLorentzContract contract+          untypedContract = convertFullContract typedContract+      in buildRenderDoc (para untypedContract)+         @?=+         "or (int %do1) (or (pair %do2 int int) (unit %do3))"+  ]
+ test/Test/Lorentz/UParam.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE DerivingStrategies #-}++-- | Tests for Lorentz 'UParam'.+module Test.Lorentz.UParam+  ( test_Simple_contract+  , test_ADT_conversion+  , unit_unpackUParam+  ) where++import Data.Vinyl.Core (Rec(..))+import Data.Constraint (Dict (..))+import Test.HUnit ((@?=), assertBool, Assertion)+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)++import Michelson.Text+import Michelson.Interpret.Pack+import Lorentz ((/->))+import qualified Lorentz as L+import Lorentz.Base+import Lorentz.UParam+import Lorentz.Run+import Michelson.Test.Dummy++-- Test on simple contract+----------------------------------------------------------------------------++type Entries = ["add" ?: Natural, "id" ?: ()]++simpleCode :: '[UParam Entries, Integer] :-> '[Integer]+simpleCode = caseUParamT+  ( #add /-> L.add+  , #id /-> L.drop @()+  ) uparamFallbackFail++test_Simple_contract :: [TestTree]+test_Simple_contract =+  [ testCase "Passing parameter 1" $+      runSimpleCode 5 (mkUParam #add 3) @?= Right 8+  , testCase "Passing parameter 2" $+      runSimpleCode 5 (mkUParam #id ()) @?= Right 5+  , testCase "Passing illegal parameter" $+      assertBool "Expected failure" $+      isLeft $+      runSimpleCode 5 (UParamUnsafe ([mt|Nyan|], ""))+  ]+  where+    runSimpleCode initVal uparam = do+      let initStack = (Identity uparam :& initVal :& RNil)+      resStack <- interpretLorentzInstr dummyContractEnv simpleCode initStack+      let Identity res :& RNil = resStack+      return res++-- Test deconstruction+----------------------------------------------------------------------------++unit_unpackUParam :: Assertion+unit_unpackUParam = do+  unpk (mkUParam #add 3) @?=+    Right ([mt|add|], "3")+  unpk (mkUParam #id ()) @?=+    Right ([mt|id|], "()")+  unpk (UParamUnsafe ([mt|gy|], mempty)) @?=+    Left (NoSuchEntryPoint [mt|gy|])+  unpk (UParamUnsafe ([mt|add|], mempty)) @?=+    Left ArgumentUnpackFailed+  where+    unpk ::+      UParam Entries ->+      Either EntryPointLookupError (MText, String)+    unpk = fmap (second show) . unpackUParam @Show++-- Test ADT conversion+----------------------------------------------------------------------------++data Parameter1+  = MyEntryPoint1 Integer+  | MyEntryPoint2 ()+  deriving Generic++type ExpectedLinearization1 =+  [ "MyEntryPoint1" ?: Integer+  , "MyEntryPoint2" ?: ()+  ]++_checkLinearizedType+  :: Dict (UParamLinearized Parameter1 ~ ExpectedLinearization1)+_checkLinearizedType = Dict++test_ADT_conversion :: [TestTree]+test_ADT_conversion =+  [ testCase "Linearization 1.1" $+      uparamFromAdt (MyEntryPoint1 5)+        @?= UParamUnsafe ([mt|MyEntryPoint1|], packValue' (L.toVal @Integer 5))+  , testCase "Linearization 1.2" $+      uparamFromAdt (MyEntryPoint2 ())+        @?= UParamUnsafe ([mt|MyEntryPoint2|], packValue' (L.toVal ()))+  ]
+ test/Test/Lorentz/UStore/Behaviour.hs view
@@ -0,0 +1,177 @@+{-# LANGUAGE DerivingStrategies #-}++-- | Tests for Lorentz 'UStore'.+module Test.Lorentz.UStore.Behaviour+  ( test_Roundtrip+  , test_Conversions+  , test_Script+  ) where++import Data.Default (def)+import qualified Data.Map as M+import Test.HUnit (Assertion, assertFailure, (@?=))+import Test.QuickCheck (Arbitrary(..))+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (testCase)++import Lorentz.Base+import Lorentz.Instr as L+import Lorentz.Run+import Lorentz.UStore+import Michelson.Test.Dummy+import Michelson.Test.Util+import Util.Test.Arbitrary ()++import Test.Util.QuickCheck (roundtripTest)+++data MyTemplate = MyTemplate+  { ints :: Integer |~> ()+  , bool :: UStoreField Bool+  } deriving stock (Eq, Show, Generic)++instance Arbitrary MyTemplate where+  arbitrary = MyTemplate <$> arbitrary <*> arbitrary++data MyTemplateBig = MyTemplateBig+  { small :: MyTemplate+  , bytes :: ByteString |~> Natural+  , total :: UStoreField Integer+  } deriving stock (Eq, Show, Generic)++instance Arbitrary MyTemplateBig where+  arbitrary = MyTemplateBig <$> arbitrary <*> arbitrary <*> arbitrary++test_Roundtrip :: [TestTree]+test_Roundtrip =+  [ roundtripTest (mkUStore @MyTemplate) ustoreDecomposeFull+  , roundtripTest (mkUStore @MyTemplateBig) ustoreDecomposeFull+  ]++test_Conversions :: [TestTree]+test_Conversions =+  [ testGroup "Simple store template"+    [ testCase "No action" $+        ustoreChangeTest+          ( nop+          , MyTemplate (UStoreSubMap def) (UStoreField False)+          , MyTemplate (UStoreSubMap def) (UStoreField False)+          )+    , testCase "Insert into submap" $+        ustoreChangeTest+          ( unit # push 5 # ustoreInsert #ints+          , MyTemplate (UStoreSubMap def) (UStoreField False)+          , MyTemplate (UStoreSubMap $ one (5, ())) (UStoreField False)+          )+    , testCase "Delete from submap" $+        ustoreChangeTest+          ( push 3 # ustoreDelete #ints+          , MyTemplate (UStoreSubMap $ one (3, ())) (UStoreField False)+          , MyTemplate (UStoreSubMap mempty) (UStoreField False)+          )+    , testCase "Get from submap" $+        ustoreChangeTest+          ( dup # push 0 # ustoreGet #ints #+            ifNone (push 10) (L.drop # push 11) # dip unit # ustoreInsert #ints+          , MyTemplate (UStoreSubMap $ one (0, ())) (UStoreField False)+          , MyTemplate (UStoreSubMap $ M.fromList [(0, ()), (11, ())]) (UStoreField False)+          )+    , testCase "Set field" $+        ustoreChangeTest+          ( push True # ustoreSetField #bool+          , MyTemplate (UStoreSubMap mempty) (UStoreField False)+          , MyTemplate (UStoreSubMap mempty) (UStoreField True)+          )+    , testCase "Get field" $+        ustoreChangeTest+          ( ustoreGetField #bool #+            if_ (push 5) (push 0) # dip unit # ustoreInsert #ints+          , MyTemplate (UStoreSubMap mempty) (UStoreField False)+          , MyTemplate (UStoreSubMap $ one (0, ())) (UStoreField False)+          )+    , testCase "Leave some entries untouched" $+        ustoreChangeTest+          ( push 0 # ustoreDelete #ints #+            unit # push 2 # ustoreInsert #ints+          , MyTemplate (UStoreSubMap $ M.fromList [(0, ()), (1, ())]) (UStoreField False)+          , MyTemplate (UStoreSubMap $ M.fromList [(1, ()), (2, ())]) (UStoreField False)+          )+    ]++  , testGroup "Non-flat store template"+    [ testCase "Custom scenario 1" $+        ustoreChangeTest+          ( push "a" # ustoreDelete #bytes #+            push 2 # push "b" # ustoreInsert #bytes #+            ustoreGetField #total # push @Integer 1 # add # ustoreSetField #total #+            unliftUStore #small #+            unit # push 0 # ustoreInsert #ints #+            push True # ustoreSetField #bool #+            liftUStore #small+          , MyTemplateBig+            { small = MyTemplate (UStoreSubMap def) (UStoreField False)+            , bytes = UStoreSubMap $ one ("a", 1)+            , total = UStoreField 10+            }+          , MyTemplateBig+            { small = MyTemplate (UStoreSubMap $ one (0, ())) (UStoreField True)+            , bytes = UStoreSubMap $ one ("b", 2)+            , total = UStoreField 11+            }+          )+    ]+  ]+  where+    -- We accept a tuple as argument to avoid many parentheses+    ustoreChangeTest+      :: (Each [Eq, Show, Generic, UStoreConversible] '[template], HasCallStack)+      => ( '[UStore template] :-> '[UStore template]+         , template+         , template+         )+      -> Assertion+    ustoreChangeTest (instr, initStoreHs, expectedNewStore) =+      let+        initStore = mkUStore initStoreHs+        ustore =+          leftToPrettyPanic $+          interpretLorentzLambda dummyContractEnv instr initStore+      in case ustoreDecomposeFull ustore of+          Left err -> assertFailure (toString err)+          Right ustoreHs -> ustoreHs @?= expectedNewStore++test_Script :: [TestTree]+test_Script =+  [ testCase "Only fields" $+      ustoreScriptTest MyTemplate+        { ints = UStoreSubMap mempty+        , bool = UStoreField True+        }++  , testCase "Fields and submaps" $+      ustoreScriptTest MyTemplate+        { ints = UStoreSubMap $ one (5, ())+        , bool = UStoreField True+        }++  , testCase "Complex" $+      ustoreScriptTest MyTemplateBig+        { small = MyTemplate (UStoreSubMap $ one (0, ())) (UStoreField True)+        , bytes = UStoreSubMap $ one ("b", 2)+        , total = UStoreField 11+        }+  ]+  where+    ustoreScriptTest+      :: (Each [Eq, Show, Generic, UStoreConversible] '[template], HasCallStack)+      => template+      -> Assertion+    ustoreScriptTest store =+      let+        filling = migrationToLambda (fillUStore store)+        ustoreFilled =+          leftToPrettyPanic $+          interpretLorentzLambda dummyContractEnv filling (mkUStore ())+      in case ustoreDecomposeFull ustoreFilled of+          Left err -> assertFailure (toString err)+          Right ustoreHs -> ustoreHs @?= store
+ test/Test/Lorentz/UStore/Migration/Batched.hs view
@@ -0,0 +1,76 @@+module Test.Lorentz.UStore.Migration.Batched+  ( test_Separated_lambdas+  ) where++import qualified Data.Map as M+import Test.HUnit ((@?=))+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (testCase)++import qualified Lorentz as L+import Lorentz.UStore+import Lorentz.UStore.Migration++import qualified Test.Lorentz.UStore.Migration.Batched.V1 as V1+import qualified Test.Lorentz.UStore.Migration.Batched.V2 as V2++initMigration :: UStoreMigrationT () V1.MyTemplate+initMigration = fillUStore V1.MyTemplate+  { bytes = UStoreSubMap $ M.fromList [(1, "a"), (2, "b")]+  , int1 = UStoreField 1+  , int2 = UStoreField 2+  , code1 = UStoreField L.nop+  , code2 = UStoreField L.int+  , code3 = UStoreField L.nop+  }++v2migration :: UStoreMigrationT V1.MyTemplate V2.MyTemplate+v2migration = mkUStoreBatchedMigration $+  muBlock $:+    L.push @Natural 1 L.#+    migrateOverwriteField #int1+  <-->+  muBlock $:+    migrateRemoveField #int2+  <-->+  muBlock $:+    -- Normally such joined blocks should not be present, but we+    -- want to test different scenarios+    L.push L.nop L.#+    migrateModifyField #code1 L.#++    migrateRemoveField #code2+  <-->+  muBlock $:+    migrateRemoveField #code3+  <-->+  migrationFinish++test_Separated_lambdas :: [TestTree]+test_Separated_lambdas =+  [ testGroup "V0 -> V1" $+      let cmigration = compileMigration mbSeparateLambdas initMigration+      in+    [ testCase "Split is correct" $+        (slbiType <$> migrationToInfo cmigration)+        @?=+        [ SlbtData+        , SlbtLambda+        , SlbtLambda+        , SlbtLambda+        ]+    ]++  , testGroup "V1 -> V2" $+      let cmigration = compileMigration mbSeparateLambdas v2migration+      in+    [ testCase "Split is correct" $+        (slbiType <$> migrationToInfo cmigration)+        @?=+        [ SlbtData+        , SlbtLambda+        , SlbtLambda+          -- Lambda removals should not be put separatelly, so one lambda is gone+        ]+    ]+  ]
+ test/Test/Lorentz/UStore/Migration/Batched/V1.hs view
@@ -0,0 +1,15 @@+module Test.Lorentz.UStore.Migration.Batched.V1+  ( MyTemplate (..)+  ) where++import Lorentz.Base+import Lorentz.UStore++data MyTemplate = MyTemplate+  { bytes :: Integer |~> ByteString+  , int1 :: UStoreField Integer+  , int2 :: UStoreField Integer+  , code1 :: UStoreField $ Lambda () ()+  , code2 :: UStoreField $ Lambda Natural Integer+  , code3 :: UStoreField $ Lambda () ()+  } deriving stock Generic
+ test/Test/Lorentz/UStore/Migration/Batched/V2.hs view
@@ -0,0 +1,12 @@+module Test.Lorentz.UStore.Migration.Batched.V2+  ( MyTemplate (..)+  ) where++import Lorentz.Base+import Lorentz.UStore++data MyTemplate = MyTemplate+  { bytes :: Integer |~> ByteString+  , int1 :: UStoreField Natural+  , code1 :: UStoreField $ Lambda () ()+  } deriving stock Generic
+ test/Test/Lorentz/UStore/Migration/FillInParts.hs view
@@ -0,0 +1,84 @@+module Test.Lorentz.UStore.Migration.FillInParts+  ( test_Migration_works+  ) where++import Fmt (pretty)+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)+import Test.HUnit ((@?=), assertFailure)++import qualified Lorentz as L+import Lorentz.UStore+import Lorentz.UStore.Migration+import Lorentz.UStore.Haskell+import Michelson.Text+import Michelson.Test.Dummy+import Lorentz.Run++data MyTemplateWrapper substore = MyTemplateWrapper+  { commonField :: UStoreField MText+  , custom :: substore+  } deriving stock (Eq, Show, Generic)++data MySubTemplatePart1 = MySubTemplatePart1+  { int :: UStoreField Integer+  , nat :: UStoreField Natural+  } deriving stock (Eq, Show, Generic)++part1Val :: MySubTemplatePart1+part1Val = MySubTemplatePart1{ int = UStoreField -1, nat = UStoreField 1 }++data MySubTemplatePart2 = MySubTemplatePart2+  { string :: UStoreField MText+  } deriving stock (Eq, Show, Generic)++part2Val :: MySubTemplatePart2+part2Val = MySubTemplatePart2{ string = UStoreField [mt|bb|] }++type MyTemplateV0 = MyTemplateWrapper ()++type MyTemplateV1 = MyTemplateWrapper (MySubTemplatePart1, MySubTemplatePart2)++migrationBatched :: UStoreMigrationT MyTemplateV0 MyTemplateV1+migrationBatched = mkUStoreBatchedMigration $+  muBlock $:+    L.push [mt|bb|] L.#+    migrateModifyField #commonField+  <-->+  fillUStoreMigrationBlock part1Val+  <-->+  fillUStoreMigrationBlock part2Val+  <-->+  migrationFinish++migrationSimple :: UStoreMigrationT MyTemplateV0 MyTemplateV1+migrationSimple = mkUStoreMigration $+  L.push [mt|bb|] L.# migrateModifyField #commonField L.#+  migrateFillUStore part1Val L.#+  migrateFillUStore part2Val L.#+  migrationFinish++test_Migration_works :: [TestTree]+test_Migration_works =+  [ ("simple migration", migrationSimple)+  , ("batched migration", migrationBatched)+  ] <&> \(desc, migration) ->+    testCase desc $ migratesToWith migration+      MyTemplateWrapper+      { commonField = UStoreField [mt|aa|]+      , custom = ()+      }+      MyTemplateWrapper+      { commonField = UStoreField [mt|bb|]+      , custom = (part1Val, part2Val)+      }+  where+    migratesToWith migration storeV1 expectedStoreV2 =+      either (assertFailure . toString) (@?= expectedStoreV2) $ do+        storeV2 <-+          first pretty $+          interpretLorentzLambda+            dummyContractEnv+            (migrationToLambda migration)+            (mkUStore storeV1)+        ustoreDecomposeFull storeV2
+ test/Test/Lorentz/UStore/Migration/Simple.hs view
@@ -0,0 +1,82 @@+module Test.Lorentz.UStore.Migration.Simple+  ( test_Migration_works+  ) where++import Fmt (pretty)+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)+import Test.HUnit ((@?=), assertFailure)++import qualified Lorentz as L+import Lorentz.UStore+import Lorentz.UStore.Migration+import Lorentz.UStore.Migration.Diff+import Michelson.Text+import Michelson.Test.Dummy+import Lorentz.Run++import qualified Test.Lorentz.UStore.Migration.Simple.V1 as V1+import qualified Test.Lorentz.UStore.Migration.Simple.V2 as V2++_checkDiff :: Proxy (BuildDiff V1.MyTemplate V2.MyTemplate)+_checkDiff = Proxy @+  [ '( 'ToAdd, '("theName", UStoreField MText))+  , '( 'ToAdd, '("transformed", UStoreField Integer))+  , '( 'ToDel, '("useless", UStoreField MText))+  , '( 'ToDel, '("transformed", UStoreField Natural))+  ]++migrationBatched :: UStoreMigrationT V1.MyTemplate V2.MyTemplate+migrationBatched = mkUStoreBatchedMigration $+  muBlock $:+    migrateExtractField #useless L.#+    L.push [mt|Token-|] L.#+    L.concat L.#+    migrateAddField #theName+  <-->+  muBlock $:+    L.push 3 L.#+    migrateOverwriteField #transformed+  <-->+  migrationFinish++migrationSimple :: UStoreMigrationT V1.MyTemplate V2.MyTemplate+migrationSimple = mkUStoreMigration $+  migrateExtractField #useless L.#+  L.push [mt|Token-|] L.#+  L.concat L.#+  migrateAddField #theName L.#++  L.push 3 L.#+  migrateOverwriteField #transformed L.#++  migrationFinish++test_Migration_works :: [TestTree]+test_Migration_works =+  [ ("simple migration", migrationSimple)+  , ("batched migration", migrationBatched)+  ] <&> \(desc, migration) ->+    testCase desc $ migratesWith migration+      V1.MyTemplate+      { V1.bytes = UStoreSubMap mempty+      , V1.count = UStoreField 5+      , V1.useless = UStoreField [mt|pog|]+      , V1.transformed = UStoreField 10+      }+      V2.MyTemplate+      { V2.theName = UStoreField [mt|Token-pog|]+      , V2.bytes = UStoreSubMap mempty+      , V2.count = UStoreField 5+      , V2.transformed = UStoreField 3+      }+  where+    migratesWith migration storeV1 expectedStoreV2 =+      either (assertFailure . toString) (@?= expectedStoreV2) $ do+        storeV2 <-+          first pretty $+          interpretLorentzLambda+            dummyContractEnv+            (migrationToLambda migration)+            (mkUStore storeV1)+        ustoreDecomposeFull storeV2
+ test/Test/Lorentz/UStore/Migration/Simple/V1.hs view
@@ -0,0 +1,13 @@+module Test.Lorentz.UStore.Migration.Simple.V1+  ( MyTemplate (..)+  ) where++import Lorentz.UStore+import Lorentz.Value++data MyTemplate = MyTemplate+  { bytes :: Integer |~> ByteString+  , count :: UStoreField Integer+  , useless :: UStoreField MText+  , transformed :: UStoreField Natural+  } deriving stock Generic
+ test/Test/Lorentz/UStore/Migration/Simple/V2.hs view
@@ -0,0 +1,13 @@+module Test.Lorentz.UStore.Migration.Simple.V2+  ( MyTemplate (..)+  ) where++import Lorentz.UStore+import Lorentz.Value++data MyTemplate = MyTemplate+  { theName :: UStoreField MText+  , bytes :: Integer |~> ByteString+  , count :: UStoreField Integer+  , transformed :: UStoreField Integer+  } deriving stock (Eq, Show, Generic)
+ test/Test/Lorentz/UStore/SafeLift.hs view
@@ -0,0 +1,42 @@+-- | We have a constraint in 'ustoreLift' which+-- forbids nested store templates with duplicated fields.+-- This module checks this constraint will work fine.+module Test.Lorentz.UStore.SafeLift+  ( test_UStore_lift+  ) where++import Data.Typeable ((:~:)(..))+import Test.Tasty (TestTree)++import Lorentz.UStore+import Lorentz.UStore.Lift++import Test.Lorentz.UStore.SafeLift.Helpers++-- Fake tests to deceive "weeder".+-- All the check consist of typechecking some stuff, see below.+test_UStore_lift :: [TestTree]+test_UStore_lift = []++_checkDuplicates0 :: UStoreFieldsAreUnique MySimpleTemplate :~: 'True+_checkDuplicates0 = Refl++data MyTemplateBig = MyTemplateBig+  { ints :: Integer |~> Natural+  , small :: MySimpleTemplate+  } deriving stock (Generic)++_checkDuplicates1 :: UStoreFieldsAreUnique MyTemplateBig :~: 'False+_checkDuplicates1 = Refl++data MyTemplate2 = MyTemplate2+  { bool :: UStoreField Bool+  } deriving Generic++data MyTemplateSuperBig = MyTemplateSuperBig+  { ssmall :: MySimpleTemplate+  , ssmall2 :: MyTemplate2+  } deriving Generic++_checkDuplicates2 :: UStoreFieldsAreUnique MyTemplateSuperBig :~: 'False+_checkDuplicates2 = Refl
+ test/Test/Lorentz/UStore/SafeLift/Helpers.hs view
@@ -0,0 +1,14 @@+-- | Contains a template for safe lifting check.+--+-- We are going to define another template with the same field name,+-- so putting this template in a separate module.+module Test.Lorentz.UStore.SafeLift.Helpers+  ( MySimpleTemplate (..)+  ) where++import Lorentz.UStore++data MySimpleTemplate = MySimpleTemplate+  { ints :: Integer |~> ()+  , bool :: UStoreField Bool+  } deriving Generic
test/Test/Macro.hs view
@@ -151,12 +151,11 @@     aIcs = InstrCallStack [LetName "a"] defPos     prim = flip Prim defPos     primEx = WithSrcEx aIcs . PrimEx-    primEx' = PrimEx     mac = flip Mac defPos     diip :: ParsedOp     diip = mac (DIIP 2 [prim SWAP])     expandedDiip :: ExpandedOp-    expandedDiip = WithSrcEx aIcs $ SeqEx [primEx' (DIP [primEx' (DIP [primEx SWAP])])]+    expandedDiip = primEx (DIPN 2 [primEx SWAP])  unit_expandValue :: Expectation unit_expandValue = do
test/Test/Michelson/Runtime.hs view
@@ -12,21 +12,23 @@ import Test.Tasty.HUnit (testCase)  import Michelson.ErrorPos (InstrCallStack(..), Pos(..), SrcPos(..))-import Michelson.Interpret (ContractEnv(..), InterpretUntypedResult(..), interpretUntyped)-import Michelson.Runtime-import Michelson.Runtime.GState (GState(..), initGState)+import Michelson.Interpret (ContractEnv(..), InterpretResult(..), interpretUntyped)+import Michelson.Runtime hiding (transfer)+import Michelson.Runtime.GState (GState(..), genesisAddress, initGState) import Michelson.Test.Dummy (dummyContractEnv, dummyMaxSteps, dummyNow, dummyOrigination)-import Michelson.Typed (untypeValue)+import Michelson.Test.Integrational+  (IntegrationalScenario, expectAnySuccess, integrationalTestExpectation, originate, transfer,+  validate) import Michelson.Text (mt)+import Michelson.Typed (untypeValue) import Michelson.Untyped-import Tezos.Address (Address(..))+import Tezos.Address import Tezos.Core (unsafeMkMutez)  test_interpreterPure :: IO [TestTree] test_interpreterPure = do   illTypedContract <-     prepareContract (Just "contracts/ill-typed/sum_strings.tz")-   pure     [ testGroup "Updates storage value of executed contract" $       [ testCase "contract1" $ updatesStorageValue contractAux1@@ -35,6 +37,11 @@     , testCase "Fails to originate an already originated contract" failsToOriginateTwice     , testCase "Fails to originate an ill-typed contract"         (failsToOriginateIllTyped (ValueString [mt||]) illTypedContract)+    , testCase "Fails transfering 0tz to plain account"+        $ integrationalTestExpectation testZeroTransactionFails+    , testCase "Success transfering 0tz to a contract"+        $ integrationalTestExpectation testZeroTransactionSuccess+    , testCase "Transfer of 0tz from unknown address is allowed" transferFromUnknown     ]  ----------------------------------------------------------------------------@@ -54,11 +61,8 @@ updatesStorageValue :: ContractAux -> Assertion updatesStorageValue ca = either (assertFailure . pretty) handleResult $ do   let-    contract = caContract ca     ce = caEnv ca-    origination = (dummyOrigination (caStorage ca) contract)-      { ooBalance = ceBalance ce-      }+    origination = contractAuxToOrigination ca     addr = mkContractAddress origination     txData = TxData       { tdSenderAddress = ceSender ce@@ -71,8 +75,8 @@       ]   (addr,) <$> interpreterPure dummyNow dummyMaxSteps initGState interpreterOps   where-    toNewStorage :: InterpretUntypedResult -> Value-    toNewStorage InterpretUntypedResult {..} = untypeValue iurNewStorage+    toNewStorage :: InterpretResult -> Value+    toNewStorage InterpretResult {..} = untypeValue iurNewStorage      handleResult :: (Address, InterpreterRes) -> Assertion     handleResult (addr, ir) = do@@ -112,6 +116,51 @@   interpreterPure dummyNow dummyMaxSteps initGState ops `shouldSatisfy`   predicate +testZeroTransactionFails :: IntegrationalScenario+testZeroTransactionFails = do+  let+    txData = TxData+        { tdSenderAddress = genesisAddress+        , tdParameter = ValueNil+        , tdAmount = unsafeMkMutez 0 }+    validator =+      \case IEZeroTransaction addr -> addr == genesisAddress+            _ -> False+  transfer txData genesisAddress+  validate $ Left validator++testZeroTransactionSuccess :: IntegrationalScenario+testZeroTransactionSuccess = do+  let+    contract = caContract contractAux1+    storage = caStorage contractAux1+    balance = ceBalance . caEnv $ contractAux1+    txData = TxData+        { tdSenderAddress = genesisAddress+        , tdParameter = caParameter contractAux1+        , tdAmount = unsafeMkMutez 0 }+  address <- originate contract "test0tzContract" storage balance+  transfer txData address+  validate $ Right expectAnySuccess++transferFromUnknown :: Assertion+transferFromUnknown =+  whenLeft (interpreterPure dummyNow dummyMaxSteps initGState interpreterOps) $+  assertFailure . pretty+  where+    ca = contractAux1+    interpreterOps =+      [ OriginateOp origination+      , TransferOp (mkContractAddress origination) txData+      ]+    origination = contractAuxToOrigination ca+    txData =+      TxData+        { tdSenderAddress = detGenKeyAddress "transferFromUnknown"+        , tdParameter = caParameter ca+        , tdAmount = unsafeMkMutez 0+        }+ ---------------------------------------------------------------------------- -- Data ----------------------------------------------------------------------------@@ -149,3 +198,9 @@       ]     }   }++contractAuxToOrigination :: ContractAux -> OriginationOperation+contractAuxToOrigination ca =+  let contract = caContract ca+      ce = caEnv ca+   in (dummyOrigination (caStorage ca) contract) {ooBalance = ceBalance ce}
+ test/Test/Michelson/Typed/Util.hs view
@@ -0,0 +1,34 @@+-- | Tests for 'Michelson.Typed.Util'.++module Test.Michelson.Typed.Util+  ( unit_linearizeLeft_sample+  , prop_linearizeLeft_performance+  ) where++import Test.HUnit (Assertion, (@?))+import Test.QuickCheck (Property, total, within)++import Michelson.Typed++unit_linearizeLeft_sample :: Assertion+unit_linearizeLeft_sample =+  isLeftLinear (linearizeLeft (rightLinear 3)) @? "Failed to linearize"++isLeftLinear :: Instr inp out -> Bool+isLeftLinear (Seq _ (Seq {})) = False+isLeftLinear (Seq a _) = isLeftLinear a+isLeftLinear _ = True++rightLinear :: Word -> Instr '[ 'TUnit, 'TUnit ] '[ 'TUnit, 'TUnit]+rightLinear = go+  where+    go 0 = SWAP+    go n = Seq SWAP (go (n - 1))++prop_linearizeLeft_performance :: Property+prop_linearizeLeft_performance =+  -- Without existing optimization it would take much more time.+  within (10 * 1000 * 1000) $ -- at most 10 sec+    total $ show @Text $ linearizeLeft instr+  where+    instr = rightLinear 300000
+ test/Test/OpSize.hs view
@@ -0,0 +1,251 @@+-- | Tests for operation size evaluation.++module Test.OpSize+  ( test_Nesting+  , test_Numbers+  , test_Values+  , test_Types+  , test_Instructions+  ) where++import Prelude hiding (EQ)++import qualified Data.Text as T+import Fmt (pretty)+import Test.HUnit (Assertion, (@?=))+import Test.QuickCheck (Arbitrary(..))+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (testCase)++import Michelson.Macro+import Michelson.OpSize+import qualified Michelson.Parser as Parser+import Michelson.Typed+import Tezos.Address+import Tezos.Core+import Tezos.Crypto++import Test.Util.Parser+import Util.Test.Arbitrary++(?==) :: HasCallStack => Text -> Word -> Assertion+codeText ?== expectedCost = do+  parsed <- Parser.codeEntry `shouldParse` ("{" <> codeText <> "}")+  let code = expandList parsed+  expandedInstrsOpSize code @?= OpSize expectedCost++(?=) :: HasCallStack => Text -> Word -> TestTree+code ?= expectedCost = testCase (toString code) $ code ?== expectedCost++{- All particular numbers below are got using dump-op-size.py script -}++test_Nesting :: [TestTree]+test_Nesting =+  [ "" ?= 0+  , "{}" ?= 5+  , "{}; {}" ?= 10+  , mconcat (replicate 100 "{}; ") ?= 500+  , "{{}}" ?= 10+  ]++test_Numbers :: [TestTree]+test_Numbers =+  [ numTestCase 0 8+  , numTestCase 1 8+  , numTestCase 2 8+  , numTestCase 63 8+  , numTestCase 64 9+  , numTestCase 65 9+  , numTestCase 2048 9+  , numTestCase 20480 10+  , numTestCase (-1) 8+  , numTestCase (-63) 8+  , numTestCase (-64) 9+  ]+  where+  numTestCase (n :: Int) gas =+    testCase (show n) $ ("PUSH int " <> show n <> "; DROP") ?== gas++test_Values :: [TestTree]+test_Values =+  [ testGroup "int"+    [ valueTestCaseExt "small" "int" "5" 8+    , valueTestCaseExt "bigger" "int" "63" 8+    , valueTestCaseExt "big" "int" "64" 9+    ]+  , valueTestCase "nat" "5" 8+  , testGroup "string"+    [ stringTestCase 0 11+    , stringTestCase 1 12+    , stringTestCase 2 13+    , stringTestCase 7 18+    , stringTestCase 8 19+    ]+  , testGroup "bytes"+    [ bytesTestCase 0 11+    , bytesTestCase 1 12+    , bytesTestCase 2 13+    , bytesTestCase 7 18+    , bytesTestCase 8 19+    ]+  , valueTestCase "mutez" "5" 8+  , valueTestCase "bool" "True" 8+  , valueTestCase "key_hash" (stringLike $ pretty (gen @KeyHash)) 47+  , testGroup "timestamp"+    [ valueTestCaseExt "small" "timestamp" "5" 8+    , valueTestCaseExt "bigger" "timestamp" "123" 9+    , valueTestCaseExt "textual" "timestamp" (stringLike "2018-08-08 00:00:00Z") 31+    ]+  , testGroup "address"+    [ valueTestCaseExt "plain tz address" "address" (stringLike $ pretty (gen @Address)) 47+    , valueTestCaseExt "plain KT address" "address" (stringLike $ pretty (gen @Address)) 47+    , let addr = gen @Address+      in valueTestCaseExt "empty entrypoint" "address" (stringLike $ pretty addr <> "%") 48+    , let epAddr = EpAddress gen (EpNameUnsafe "a")+      in valueTestCaseExt "short entrypoint" "address" (stringLike $ pretty epAddr) 49+    , let epAddr = EpAddress gen (EpNameUnsafe . mconcat $ replicate 8 "a")+      in valueTestCaseExt "long entrypoint" "address" (stringLike $ pretty epAddr) 56+    ]+  -- ed25519 and secp256k1 keys have different size+  , valueTestCase "key" (stringLike $ pretty (PublicKeyEd25519 gen)) 65+  , valueTestCase "key" (stringLike $ pretty (PublicKeySecp256k1 gen)) 66+  , valueTestCase "unit" "Unit" 8+  , valueTestCase "signature" (stringLike $ pretty (gen @Signature)) 110+  , testGroup "chain_id"+    [ valueTestCase "chain_id" (stringLike $ pretty dummyChainId) 26+    , valueTestCase "chain_id" "0x00000000" 15+    ]+  , testGroup "option"+    [ valueTestCaseExt "none" "(option int)" "None" 10+    , valueTestCaseExt "some" "(option int)" "(Some 5)" 12+    ]+  , testGroup "list"+    [ valueTestCaseExt "Empty" "(list int)" "{}" 13+    , valueTestCaseExt "Length 1" "(list int)" "{1}" 15+    , valueTestCaseExt "Length 8" "(list int)" "{1;1;1;1;1;1;1;1}" 29+    ]+  , testGroup "set"+    [ valueTestCaseExt "Empty" "(set int)" "{}" 13+    , valueTestCaseExt "Length 1" "(set int)" "{1}" 15+    , valueTestCaseExt "Length 1" "(set int)" "{1;2;3;4;5;6;7;8}" 29+    ]+  , valueTestCaseExt "pair" "(pair int int)" "(Pair 1 2)" 16+  , valueTestCaseExt "or" "(or int int)" "(Left 1)" 14+  , testGroup "lambda"+    [ valueTestCaseExt "empty lambda" "(lambda int int)" "{}" 15+    , valueTestCaseExt "simple lambda" "(lambda int int)" "{DUP; DROP}" 19+    ]+  , testGroup "map"+    [ valueTestCaseExt "Empty" "(map int int)" "{}" 15+    , valueTestCaseExt "Length 1" "(map int int)" "{Elt 1 2}" 21+    , valueTestCaseExt "Length 1 (big key)" "(map int int)" "{Elt 100 2}" 22+    , let val = "{Elt 1 1; Elt 2 2; Elt 3 3; Elt 4 4; \+                \ Elt 5 5; Elt 6 6; Elt 7 7; Elt 8 8 }"+      in valueTestCaseExt "Length 8" "(map int int)" val 63+    ]+  ]+  where+    valueTestCaseExt name ty val gas =+      testCase name $+        ("PUSH " <> ty <> " " <> val <> "; DROP") ?== gas+    valueTestCase ty val gas =+      valueTestCaseExt (toString ty) ty val gas+    stringTestCase l gas =+      let name = "Length " <> show l+          val = stringLike $ T.replicate l "a"+      in valueTestCaseExt name "string" val gas+    bytesTestCase l gas =+      let name = "Length " <> show l+          val = "0x" <> T.replicate l "12"+      in valueTestCaseExt name "bytes" val gas++    stringLike x = "\"" <> x <> "\""+    gen :: Arbitrary a => a+    gen = runGen 12 arbitrary++test_Types :: [TestTree]+test_Types =+  [ typeTestCase "int" 8+  , typeTestCase "string" 8+  , typeTestCase "mutez" 8+  , typeTestCase "key_hash" 8+  , typeTestCase "address" 8+  , typeTestCase "signature" 8+  , typeTestCase "option int" 10+  , typeTestCase "list int" 10+  , typeTestCase "set int" 10+  , typeTestCase "contract int" 10+  , typeTestCase "pair int int" 12+  , typeTestCase "or int int" 12+  , typeTestCase "or (pair nat nat) (pair int nat)" 20+  , typeTestCase "lambda int unit" 12+  , typeTestCase "map int int" 12+  , typeTestCase "big_map int int" 12+  , typeTestCase "lambda operation int" 12++  , typeTestCase "pair int int" 12+  , typeTestCase "pair (int :a) int" 18+  , typeTestCase "pair (int %a) int" 18+  , typeTestCase "pair (int %a :a) int" 21+  , typeTestCase "pair (int %a) (int %a)" 24+  , typeTestCase "pair :a (int %a) (int %a)" 30+  , typeTestCase "pair :a int (int %a)" 24+  , typeTestCase "pair :a (int %a :a) (int %a)" 33+  ]+  where+  typeTestCase t gas =+    testCase (show t) $ ("DUP; CONTRACT " <> t <> "; DROP") ?== gas++test_Instructions :: [TestTree]+test_Instructions =+  [ customInstrTestCase "FAILWITH" 2+  , customInstrTestCase "FAIL" 9++  , instrTestCase "DUP" 4+  , instrTestCase "DUP @a" 10+  , instrTestCase "DUP; DROP" 6+  , instrTestCase "DUP; SWAP" 6+  , instrTestCase "DUP; SWAP; SWAP" 8+  , instrTestCase "PUSH int 0" 8+  , instrTestCase "PUSH @a int 0" 14+  , instrTestCase "PUSH @a (int :a) 0" 20+  , instrTestCase "SOME" 4+  , instrTestCase "SOME @a" 10+  , instrTestCase "SOME @a" 10+  , instrTestCase "NONE int" 6+  , instrTestCase "NONE (option int)" 8+  , instrTestCase "NONE :a @a (option :a int)" 23+  , instrTestCase "UNIT" 4+  , instrTestCase "DUP; SOME; IF_NONE {}{DROP}" 20+  , instrTestCase "DUP; DUP; PAIR" 8+  , instrTestCase "DUP; DUP; PAIR %a" 14+  , instrTestCase "DUP; DUP; PAIR %a %a" 17+  , instrTestCase "DUP; DUP; PAIR %a %a :a" 20+  , instrTestCase "DUP; DUP; PAIR %a %a :a @a" 23+    -- Further skipping some instructions since everything is trivial+  , instrTestCase "EMPTY_BIG_MAP :a @a (int :a) (unit :a)" 29+  , instrTestCase "PUSH (list int) {}; MAP {}" 20+  , instrTestCase "DIP {}" 9+  , instrTestCase "DIP 0 {}" 11+  , instrTestCase "DIP 1 {}" 11+  , instrTestCase "DROP 0" 6+  , instrTestCase "PACK" 4+  , instrTestCase "PUSH int 1; PUSH int 2; ADD" 16+  , instrTestCase "DUP; CONTRACT int" 8++  , instrTestCase "UNIT; PUSH mutez 5; NONE key_hash; \+                  \CREATE_CONTRACT \+                    \{ parameter unit; \+                    \  storage unit; \+                    \  code { CDR; NIL operation; PAIR } }" 44+  , instrTestCase "PUSH (or int nat) (Left 5); PUSH mutez 5; NONE key_hash; \+                  \CREATE_CONTRACT \+                    \{ parameter unit; \+                    \  storage (or int nat); \+                    \  code { DROP; PUSH (or int nat) (Right 2); NIL operation; PAIR } }" 70+  ]+  where+  customInstrTestCase instr gas =+    testCase (show instr) $ instr ?== gas+  instrTestCase instr gas =+    customInstrTestCase (instr <> "; FAILWITH") gas
+ test/Test/Optimizer.hs view
@@ -0,0 +1,123 @@+-- | Tests for optimizer.++module Test.Optimizer+  ( unit_Optimize_DROP_n+  , unit_Optimize_DIP_n+  , unit_Redundant_DIP+  , unit_UNPAIR_DROP+  , unit_Optimize_PUSH_PACK+  , unit_Sample_optimize+  ) where++import Prelude hiding (EQ)++import Test.HUnit (Assertion, (@?=))+import Data.Default (def)++import Michelson.Optimizer+import Michelson.Text+import qualified Michelson.Typed as T+import Michelson.Typed.Instr+import Michelson.Interpret.Pack (packValue')+import Michelson.Untyped (CT(..))+import Util.Peano (Sing (..))++-- Sample stacks of length 0, 1…+type Stack0 = '[ ]+type Stack1 = '[ 'T.TUnit ]+type Stack1Int = '[ 'T.Tc 'CInt ]+type Stack1Pair = '[ 'T.TPair 'T.TUnit 'T.TUnit ]+type Stack2 = '[ 'T.TUnit, 'T.TUnit ]+type Stack2UnitInt = '[ 'T.TUnit, 'T.Tc 'CInt ]++unit_Optimize_DROP_n :: Assertion+unit_Optimize_DROP_n = do+  optimize @Stack0 @Stack0 (DROPN SZ) @?= Nop+  -- Sadly it is not optimized (yet).+  optimize @Stack1 @Stack0 (DROPN (SS SZ)) @?= DROPN (SS SZ)++unit_Optimize_DIP_n :: Assertion+unit_Optimize_DIP_n = do+  optimize @Stack1 @Stack0 (DIPN SZ DROP) @?= DROP+  -- Sadly it is not optimized (yet).+  optimize @Stack1 @Stack2 (DIPN (SS SZ) UNIT) @?= (DIPN (SS SZ) UNIT)++unit_Redundant_DIP :: Assertion+unit_Redundant_DIP = do+  optimize @Stack1Int @Stack1 (DIP UNIT `Seq` DROP) @?= (DROP `Seq` UNIT)+  optimize @Stack1Int @Stack2UnitInt (UNIT `Seq` DIP (DUP `Seq` MUL)) @?= (DUP `Seq` MUL `Seq` UNIT)++unit_UNPAIR_DROP :: Assertion+unit_UNPAIR_DROP = do+  -- The left is `unpair # DROP` which is essentially just `cdr`,+  -- but we do not optimize it fully yet (we only remove redundant DIP).+  -- TODO [TM-354]: it does not work if don't manually enforce right-linear structure.+  optimize @Stack1Pair @Stack1 (DUP `Seq` (CAR `Seq` (DIP CDR `Seq` DROP))) @?= (DUP `Seq` CAR `Seq` DROP `Seq` CDR)++unit_Optimize_PUSH_PACK :: Assertion+unit_Optimize_PUSH_PACK =+  optimize'+    (PUSH strValue `Seq` PACK `Seq` DUP) @?=+    (PUSH (T.VC $ T.CvBytes $ packValue' strValue) `Seq` DUP)+  where+    optimize' =+      optimizeWithConf @Stack0 @'[ 'T.Tc 'CBytes, 'T.Tc 'CBytes ]+      (def {ruleset = defaultRulesAndPushPack})++unit_Sample_optimize :: Assertion+unit_Sample_optimize = optimize nonOptimal @?= expectedOptimized++str :: MText+str = [mt|aa|]++strValue :: T.Value ('T.Tc 'CString)+strValue = T.VC $ T.CvString str++nonOptimal :: T.Contract ('T.Tc 'CString) ('T.Tc 'CString)+nonOptimal =+  CAR `Seq`+  -- `PUSH; DROP` is erased+  -- We also arbitrarily group two instructions here to make+  -- structure definitely non-linear.+  (PUSH strValue `Seq` SWAP `Seq` SWAP `Seq` DROP) `Seq`+  -- If we PUSH and then DIP, DIP is not necessary+  PUSH strValue `Seq`+  -- `DUP; DROP` is also erased+  DIP (DUP `Seq` DUP `Seq` DROP) `Seq`+  -- `SWAP; SWAP` is erased, along with surrounding redundant instructions and outer `DIP`+  DIP (PUSH (T.VC $ T.CvBool False) `Seq` IF (Nop) (SWAP `Seq` SWAP)) `Seq`+  CONCAT `Seq`+  Nested (SIZE `Seq`+  -- `COMPARE` with 0 is redundant+  (PUSH (T.VC $ T.CvNat 0) `Seq` COMPARE) `Seq` EQ `Seq`+  -- Here both bodys of `IF` can be erased and then `IF` can be replaced with `DROP`+  IF (DUP `Seq` DROP) (UNIT `Seq` DROP) `Seq`+  -- `LEFT` followed by `IF_LEFT` can be optimized+  LEFT @('T.TKey) `Seq` IF_LEFT Nop (UNIT `Seq` FAILWITH) `Seq`+  -- SWAP is redundant after DUP+  DUP `Seq` SWAP `Seq` CONCAT `Seq`+  -- `DIP Nop` is thrown away+  DIP (UNIT `Seq` DROP) `Seq`+  -- Finish, nothing to optimize here+  NIL `Seq` PAIR)++-- Auxiliary operator to produce right linear sequence.  We do not use+-- it above because input instruction can have arbitrary structure,+-- but we know that the output is right balanced. In practice we can't+-- check it though, because that's how our 'Eq' is defined.+(#<#) :: T.Instr a b -> T.Instr b c -> T.Instr a c+(#<#) = Seq+infixr 1 #<#++-- Expected output of the optimizer.+expectedOptimized :: T.Contract ('T.Tc 'CString) ('T.Tc 'CString)+expectedOptimized =+  CAR #<#+  DUP #<#+  PUSH strValue #<#+  CONCAT #<#+  SIZE #<#+  INT #<# EQ #<#+  DROP #<#+  DUP #<# CONCAT #<#+  NIL #<# PAIR
test/Test/Parser.hs view
@@ -1,16 +1,17 @@ module Test.Parser   ( unit_Parse_contracts+  , unit_Parse_bad_contracts   , unit_Value   , unit_string_literal   , unit_IF   , unit_MAP   , unit_PAIR   , unit_pair_type+  , unit_tuple_type   , unit_or_type   , unit_lambda_type   , unit_list_type   , unit_set_type-  , unit_explicitType   , unit_Pair_constructor   , unit_PrintComment   , unit_ParserException@@ -20,26 +21,38 @@ import qualified Data.List.NonEmpty as NE import Test.Hspec.Expectations (Expectation, expectationFailure, shouldBe, shouldSatisfy) import Text.Megaparsec (parse)-import Text.Megaparsec.Error (ErrorFancy(ErrorCustom), ParseError(FancyError), bundleErrors)+import Text.Megaparsec.Error+  (ErrorFancy(ErrorCustom), ParseError(FancyError), bundleErrors, errorBundlePretty)  import Michelson.ErrorPos (srcPos) import Michelson.Macro as Mo import Michelson.Parser as P import Michelson.Untyped as Mo import Util.IO+import Util.Positive -import Test.Util.Contracts (getIllTypedContracts, getWellTypedContracts)+import Test.Util.Contracts (getIllTypedContracts, getUnparsableContracts, getWellTypedContracts)  unit_Parse_contracts :: Expectation unit_Parse_contracts = do   files <- mappend <$> getWellTypedContracts <*> getIllTypedContracts-  mapM_ checkFile files-  where-    checkFile :: FilePath -> Expectation-    checkFile file = do-      code <- readFileUtf8 file-      parse P.program file code `shouldSatisfy` isRight+  mapM_ (checkFile True) files +unit_Parse_bad_contracts :: Expectation+unit_Parse_bad_contracts = do+  files <- getUnparsableContracts+  mapM_ (checkFile False) files++checkFile :: Bool -> FilePath -> Expectation+checkFile shouldParse file = do+  code <- readFileUtf8 file+  case parse P.program file code of+    Left err+      | shouldParse -> expectationFailure $ errorBundlePretty err+    Right _+      | not shouldParse -> expectationFailure $ "Managed to parse " <> file+    _ -> pass+ unit_Value :: Expectation unit_Value = do   P.parseNoEnv P.value "" "{}" `shouldBe`@@ -56,6 +69,19 @@     (Right . Mo.ValueMap $ NE.fromList       [Mo.Elt (Mo.ValueInt 1) (Mo.ValueInt 2), Mo.Elt (Mo.ValueInt 3) (Mo.ValueInt 4)]     )+  P.parseNoEnv P.value "" "{DIP DROP;}" `shouldBe`+    Right (Mo.ValueLambda (Mo.Prim (Mo.DIP [Mo.Prim Mo.DROP (srcPos 0 5)]) (srcPos 0 1) :| []))+  P.parseNoEnv P.value "" "{DIP DROP;somecontent}" `shouldSatisfy` isLeft+  P.parseNoEnv P.value "" "{{ }; {}; {PUSH int 5; DROP}}" `shouldBe`+    Right (Mo.ValueLambda (Mo.Seq [] (srcPos 0 1)+            :| [ Mo.Seq [] (srcPos 0 6)+               , Mo.Seq [Mo.Prim (Mo.PUSH noAnn (Mo.Type (Mo.Tc Mo.CInt) noAnn) (Mo.ValueInt 5)) (srcPos 0 11)+                        , Mo.Prim Mo.DROP (srcPos 0 23)] (srcPos 0 10)+               ]+           ))+  P.parseNoEnv P.value "" "{{}; {}; {5}}" `shouldBe`+    Right (Mo.ValueSeq (Mo.ValueNil :| [Mo.ValueNil, Mo.ValueSeq (Mo.ValueInt 5 :| [])]))+  P.parseNoEnv P.value "" "{{}; {5}; {Push int 5}}" `shouldSatisfy` isLeft  unit_string_literal :: Expectation unit_string_literal = do@@ -97,21 +123,28 @@ unit_pair_type = do   P.parseNoEnv P.type_ "" "pair unit unit" `shouldBe` Right unitPair   P.parseNoEnv P.type_ "" "(unit, unit)" `shouldBe` Right unitPair-  P.parseNoEnv P.type_ "" "(Parameter, (int, (Storage, bool)))"+  P.parseNoEnv P.type_ "" "(key, (int, (string, bool)))"     `shouldSatisfy` isRight-  P.parseNoEnv P.type_ "" "(Parameter, Parameter, Storage, bool)"+  P.parseNoEnv P.type_ "" "(signature, chain_id, string, bool)"     `shouldSatisfy` isRight   where     unitPair :: Mo.Type     unitPair =       Mo.Type (Mo.TPair noAnn noAnn (Mo.Type Mo.TUnit noAnn) (Mo.Type Mo.TUnit noAnn)) noAnn +unit_tuple_type :: Expectation+unit_tuple_type = do+  P.parseNoEnv P.type_ "" "(int, int, bool, unit, nat)"+    `shouldBe` Right (typair (typair tyint tyint) (typair tybool (typair tyunit tynat)))+ unit_or_type :: Expectation unit_or_type = do   P.parseNoEnv P.type_ "" "or unit unit" `shouldBe` Right unitOr   P.parseNoEnv P.type_ "" "(unit | unit)" `shouldBe` Right unitOr-  P.parseNoEnv P.type_ "" "Parameter | (int | (Storage | bool)))"+  P.parseNoEnv P.type_ "" "(chain_id | (int | (string | bool)))"     `shouldSatisfy` isRight+  P.parseNoEnv P.type_ "" "or unit unit kek"+    `shouldSatisfy` isLeft   where     unitOr :: Mo.Type     unitOr =@@ -121,7 +154,7 @@ unit_lambda_type = do   P.parseNoEnv P.type_ "" "lambda unit unit" `shouldBe` Right lambdaUnitUnit   P.parseNoEnv P.type_ "" "\\unit -> unit" `shouldBe` Right lambdaUnitUnit-  P.parseNoEnv P.type_ "" "lambda int (Storage, int)" `shouldSatisfy` isRight+  P.parseNoEnv P.type_ "" "lambda int (signature, int)" `shouldSatisfy` isRight   where     lambdaUnitUnit :: Mo.Type     lambdaUnitUnit =@@ -131,7 +164,7 @@ unit_list_type = do   P.parseNoEnv P.type_ "" "list unit" `shouldBe` Right unitList   P.parseNoEnv P.type_ "" "[unit]" `shouldBe` Right unitList-  P.parseNoEnv P.type_ "" "[(Parameter, Storage)]" `shouldSatisfy` isRight+  P.parseNoEnv P.type_ "" "[(key, key)]" `shouldSatisfy` isRight   where     unitList :: Mo.Type     unitList =@@ -146,17 +179,6 @@     intSet =       Mo.Type (Mo.TSet (Mo.Comparable Mo.CInt noAnn)) noAnn -unit_explicitType :: Expectation-unit_explicitType = do-  P.parseNoEnv P.explicitType "" "Parameter" `shouldSatisfy` isLeft-  P.parseNoEnv P.explicitType "" "Storage" `shouldSatisfy` isLeft-  P.parseNoEnv P.explicitType "" "List Parameter" `shouldSatisfy` isLeft-  P.parseNoEnv P.explicitType "" "Void int Parameter" `shouldSatisfy` isLeft-  P.parseNoEnv P.explicitType "" "(Parameter, (int, (bool, Storage)))"-    `shouldSatisfy` isLeft-  P.parseNoEnv P.explicitType "" "int"-    `shouldBe` (Right $ Mo.Type (Mo.Tc Mo.CInt) noAnn)- unit_Pair_constructor :: Expectation unit_Pair_constructor = do   P.parseNoEnv P.value "" "Pair Unit Unit" `shouldBe` Right unitPair@@ -195,6 +217,12 @@     (StringLiteralException (InvalidChar '\n'))   handleCustomError "\"aaa\r\"" P.stringLiteral     (StringLiteralException (InvalidChar '\r'))+  handleCustomError "{ TAG 2 (int | string) }" P.codeEntry+    (WrongTagArgs 2 (PositiveUnsafe 2))+  handleCustomError "{ ACCESS 2 2 }" P.codeEntry+    (WrongAccessArgs 2 (PositiveUnsafe 2))+  handleCustomError "{ SET 2 2 }" P.codeEntry+    (WrongSetArgs 2 (PositiveUnsafe 2))   where     handleCustomError       :: HasCallStack => Text -> Parser a -> CustomParserException -> Expectation@@ -202,13 +230,16 @@       case P.parseNoEnv parser "" text of         Right _ -> expectationFailure "expecting parser to fail"         Left bundle -> case toList $ bundleErrors bundle of-          [FancyError _ errorSet] -> case toList errorSet of-            [(ErrorCustom e)] -> e `shouldBe` customException-            _ -> expectationFailure "expecting single ErrorCustom"-          _ -> expectationFailure "expecting single ErrorCustom"+          [FancyError _ (toList -> [ErrorCustom e])] ->+            e `shouldBe` customException+          _ ->+            expectationFailure $+              "expecting single ErrorCustom, but got " <>+              errorBundlePretty bundle  unit_letType :: Expectation unit_letType = do   P.parseNoEnv P.letType "" "type kek = int" `shouldSatisfy` isRight-  P.parseNoEnv P.letType "" "type Parameter = int" `shouldSatisfy` isLeft-  P.parseNoEnv P.letType "" "type Storage = int" `shouldSatisfy` isLeft+  -- They used to be prohibited, but now we permit them.+  P.parseNoEnv P.letType "" "type Parameter = int" `shouldSatisfy` isRight+  P.parseNoEnv P.letType "" "type Storage = int" `shouldSatisfy` isRight
+ test/Test/Preprocess.hs view
@@ -0,0 +1,58 @@+-- | Tests for preprocessing.++module Test.Preprocess+  ( unit_Sample_preprocess+  ) where++import Prelude hiding (EQ)++import Test.HUnit (Assertion, (@?=))++import Michelson.Preprocess+import Michelson.Text+import qualified Michelson.Typed as T+import Michelson.Typed.Instr+import Michelson.Untyped (CT(..))++unit_Sample_preprocess :: Assertion+unit_Sample_preprocess = transformStrings False f sample @?= expected+  where+    f s+      | s == str1 = str5+      | s == str2 = str4+      | s == str4 = str2+      | s == str5 = str1+      | otherwise = s++str1, str2, str3, str4, str5 :: MText+str1 = [mt|aa|]+str2 = [mt|ls|]+str3 = [mt|gulya|]+str4 = [mt|naiks|]+str5 = [mt|eek|]++sample :: T.Contract ('T.Tc 'CString) ('T.Tc 'CString)+sample =+  CAR `Seq`+  PUSH (toStr str1) `Seq`+  DIP (PUSH (toStr str2)) `Seq`+  LEFT @('T.TKey) `Seq` IF_LEFT Nop (PUSH (toStr str4)  `Seq` FAILWITH) `Seq`+  DIP (DIP (PUSH (toStr str5))) `Seq`+  PUSH (toStr str3) `Seq`+  DROP `Seq` DROP `Seq` DROP `Seq` DROP `Seq`+  NIL `Seq` PAIR+  where+    toStr = T.VC . T.CvString++expected :: T.Contract ('T.Tc 'CString) ('T.Tc 'CString)+expected =+  CAR `Seq`+  PUSH (toStr str5) `Seq`+  DIP (PUSH (toStr str4)) `Seq`+  LEFT @('T.TKey) `Seq` IF_LEFT Nop (PUSH (toStr str2)  `Seq` FAILWITH) `Seq`+  DIP (DIP (PUSH (toStr str1))) `Seq`+  PUSH (toStr str3) `Seq`+  DROP `Seq` DROP `Seq` DROP `Seq` DROP `Seq`+  NIL `Seq` PAIR+  where+    toStr = T.VC . T.CvString
test/Test/Printer/Michelson.hs view
@@ -1,20 +1,75 @@+{-# LANGUAGE DeriveAnyClass #-}+ module Test.Printer.Michelson-  ( unit_Roundtrip+  ( unit_Erase_annotations+  , unit_Roundtrip   , unit_let_macro+  , unit_PrettyPrint+  , unit_PrintTypedNotes+  , unit_PrintSmartParens   ) where +import qualified Data.Map.Lazy as Map+import Data.Text.Lazy (strip) import Fmt (pretty)-import Test.HUnit (Assertion, assertEqual, assertFailure, (@?=)) import Generics.SYB (everywhere, mkT)+import Test.HUnit (Assertion, assertEqual, assertFailure, (@?=)) -import Michelson.Printer (printUntypedContract)+import qualified Lorentz as L+import Michelson.Printer (printSomeContract, printUntypedContract) import Michelson.Runtime (parseExpandContract)+import Michelson.TypeCheck.Instr (typeCheckContract)+ import Michelson.Test (importUntypedContract)-import Michelson.Untyped.Instr (ExpandedOp(..)) import qualified Michelson.Untyped as U+import Michelson.Untyped.Instr (ExpandedOp(..))+import Util.IO (readFileUtf8)  import Test.Util.Contracts+import Test.Util.HUnit +-- | Check that contract under the first given file, when parsed and printed+-- back, produces the contract under the second file.+printerTest :: (FilePath, FilePath) -> Assertion+printerTest (srcPath, refPath) = do+  contract <- importUntypedContract srcPath+  case typeCheckContract Map.empty contract of+    Left err -> assertFailure ("Failed to typecheck contract " <> srcPath <> ": " <> pretty err)+    Right checkedContract -> do+      targetSrc <- strip . fromStrict <$> readFileUtf8 refPath+      assertEqualBuild+        ("Prettifying " <> srcPath <> " does not match the expected format")+        targetSrc+        (printSomeContract False checkedContract)++unit_PrintTypedNotes :: Assertion+unit_PrintTypedNotes = do+  contracts <- getContractsWithReferences ".tz" "contracts/notes-in-typed-contracts" "ref"+  mapM_ printerTest contracts++unit_PrintSmartParens :: Assertion+unit_PrintSmartParens = do+  contracts <- getContractsWithReferences ".tz" "contracts/smart-parens" "ref"+  mapM_ printerTest contracts++unit_PrettyPrint :: Assertion+unit_PrettyPrint = do+  contracts <- getContractsWithReferences ".tz" "contracts/pretty" "pretty"+  mapM_ prettyTest contracts+  where+    prettyTest :: (FilePath, FilePath) -> Assertion+    prettyTest (srcPath, refPath) = do+      contract <- importUntypedContract srcPath+      targetSrc <- strip . fromStrict <$> readFileUtf8 refPath+      assertEqual+        ("Prettifying " <> srcPath <> " does not match the expected format")+        (printUntypedContract False contract)+        targetSrc+      assertEqual+        ("Single line pretty printer output "+          <> srcPath <> " contain new lines.")+        (find (=='\n') $ printUntypedContract True contract) Nothing+ unit_Roundtrip :: Assertion unit_Roundtrip = do   morleyContractFiles <- getWellTypedMorleyContracts@@ -30,8 +85,8 @@       -- because during printing we lose extra instructions.       assertEqual ("After printing and parsing " <> filePath <>                    " is printed differently")-        (printUntypedContract contract1)-        (printUntypedContract contract2)+        (printUntypedContract True contract1) -- using single line output here+        (printUntypedContract True contract2)     michelsonRoundtripPrintTest :: FilePath -> Assertion     michelsonRoundtripPrintTest filePath = do       contract1 <- importUntypedContract filePath@@ -48,13 +103,31 @@   let ops = concatMap U.flattenExpandedOp (U.code contract)   ops @?= [U.CDR U.noAnn U.noAnn, U.UNIT U.noAnn U.noAnn, U.DROP] +data TestParam+  = TestCon1 ("a" L.:! Natural, "b" L.:! Bool)+  | TestCon2 ()+  deriving stock Generic+  deriving anyclass L.IsoValue++instance L.ParameterEntryPoints TestParam where+  parameterEntryPoints = L.pepRecursive++unit_Erase_annotations :: Assertion+unit_Erase_annotations =+  let+    contract :: L.Contract TestParam ()+    contract = L.cdr L.# L.nil L.# L.pair+    expected = "parameter (or (pair %testCon1 (nat :a) (bool :b)) (unit %testCon2));storage unit;code { CAST (pair (or (pair nat bool) unit) unit);CDR;NIL operation;PAIR };"+  in assertEqual+      "Lorentz contract erases parameter annotations when printed"+      expected (L.printLorentzContract True contract)+ printAndParse :: FilePath -> U.Contract -> IO U.Contract printAndParse fp contract1 =-  case parseExpandContract (Just fp) (toText $ printUntypedContract contract1) of+  case parseExpandContract (Just fp) (toText $ printUntypedContract True contract1) of     Left err ->       assertFailure ("Failed to parse printed " <> fp <> ": " <> pretty err)     Right contract2 -> pure contract2-  -- | Remove all `WithSrcEx` from contract code because `SrcPos`es -- and such stuff can change during printing and parsing
test/Test/Serialization/Michelson.hs view
@@ -6,6 +6,7 @@  import Prelude hiding (Ordering(..)) +import Data.Default (def) import Data.Singletons (SingI(..)) import qualified Data.Text as T import Data.Typeable ((:~:)(..), Typeable, eqT, typeRep)@@ -17,13 +18,13 @@ import Michelson.Macro (expandList) import qualified Michelson.Parser as Parser import Michelson.Test.Util+import Michelson.Text import Michelson.TypeCheck (HST(..), SomeInstr(..), SomeInstrOut(..), typeCheckList) import Michelson.Typed-import Michelson.Text import Michelson.Untyped (noAnn) import Test.Util.Parser import Tezos.Address (Address(..), unsafeParseAddress)-import Tezos.Core (Mutez, Timestamp, timestampFromSeconds, unsafeMkMutez)+import Tezos.Core (Mutez, Timestamp, parseChainId, timestampFromSeconds, unsafeMkMutez) import Tezos.Crypto (KeyHash(..), parseKeyHash, parsePublicKey, parseSignature)  spec_Packing :: Spec@@ -43,6 +44,7 @@     keyTest     unitTest     signatureTest+    chainIdTest     optionTest     listTest     setTest@@ -56,36 +58,45 @@     typesTest    unpackNegTest+  readableUnpackTest  stripOptional0x :: Text -> Text stripOptional0x h = T.stripPrefix "0x" h ?: h  -- | Dummy wrapper for what do we test - pack or unpack.-data TestMethod = TestMethod+data TestMethod t = TestMethod   { _tmName :: String-  , _tmApply-      :: forall t. (Typeable t, SingI t, HasNoOp t, HasNoBigMap t)-      => Value t -> Text -> Expectation+  , _tmApply :: Value t -> Text -> Expectation   } -testMethods :: HasCallStack => [TestMethod]-testMethods =-  [ TestMethod "Pack" $-      \val encodedHex ->-        encodeHex (packValue' val) `shouldBe` stripOptional0x encodedHex+packTestMethods+  :: (PackedValScope t, HasCallStack)+  => [TestMethod t]+packTestMethods = one $+  TestMethod "Pack" $+    \val encodedHex ->+      encodeHex (packValue' val) `shouldBe` stripOptional0x encodedHex -  , TestMethod "Unpack" $-      \val encodedHex ->-        let encoded = decodeHex (stripOptional0x encodedHex)-                      ?: error ("Invalid hex: " <> show encodedHex)-        in runUnpack mempty encoded-            `shouldBe` Right val-  ]+unpackTestMethods+  :: (UnpackedValScope t, HasCallStack)+  => [TestMethod t]+unpackTestMethods = one $+  TestMethod "Unpack" $+    \val encodedHex ->+      let encoded = decodeHex (stripOptional0x encodedHex)+                    ?: error ("Invalid hex: " <> show encodedHex)+      in runUnpack encoded+          `shouldBe` Right val +allTestMethods+  :: (UnpackedValScope t, HasCallStack)+  => [TestMethod t]+allTestMethods = packTestMethods <> unpackTestMethods+ packSpecManual-    :: (Show x, Typeable t, SingI t, HasNoOp t, HasNoBigMap t, HasCallStack)-    => String -> (x -> Value t) -> [(x, Text)] -> Spec-packSpecManual name toVal' suites =+    :: (Show x, HasCallStack)+    => String -> [TestMethod t] -> (x -> Value t) -> [(x, Text)] -> Spec+packSpecManual name testMethods toVal' suites =   forM_ @[_] testMethods $ \(TestMethod mname method) ->     describe mname $       describe name $ forM_ suites $ \(x, h) ->@@ -93,11 +104,13 @@  packSpec   :: forall x (t :: T).-     (Typeable t, IsoValue x, Show x, ToT x ~ t, SingI t, HasNoOp t, HasNoBigMap t-     , HasCallStack)+     ( IsoValue x, Show x, ToT x ~ t+     , Typeable t, UnpackedValScope t+     , HasCallStack+     )   => [(x, Text)]   -> Spec-packSpec = packSpecManual typeName toVal+packSpec = packSpecManual typeName allTestMethods toVal   where     typeName = show $ typeRep (Proxy @(Value t)) @@ -108,11 +121,11 @@   -> [(Text, Text)]   -> Spec parsePackSpec name suites =-  forM_ @[_] testMethods $ \(TestMethod mname method) ->+  forM_ @[_] allTestMethods $ \(TestMethod mname method) ->     describe mname $       describe name $ forM_ suites $ \(codeText, packed) ->         it (truncateName $ toString codeText) $ do-          parsed <- Parser.codeEntry `shouldParse` codeText+          parsed <- Parser.codeEntry `shouldParse` ("{" <> codeText <> "}")           let code = expandList parsed           let _ :/ typed = typeCheckList code initStack                 & runExceptT@@ -121,12 +134,12 @@            case typed of             AnyOutInstr instr ->-              method (VLam @inp @out instr) packed+              method (VLam @inp @out $ RfAlwaysFails instr) packed              (instr :: Instr '[inp] outs) ::: _ ->               case eqT @'[out] @outs of                 Just Refl ->-                  method (VLam @inp @out instr) packed+                  method (VLam @inp @out $ RfNormal instr) packed                 Nothing ->                   error "Output type unexpectedly mismatched"   where@@ -134,17 +147,17 @@       | length s < 60 = s       | otherwise = take 60 s <> " ..."     initTypeCheckST = error "Type check state is not defined"-    initStack = (sing @inp, NStar, noAnn) ::& SNil+    initStack = (sing @inp, starNotes, noAnn) ::& SNil  unpackNegSpec   :: forall (t :: T).-      (SingI t, HasNoOp t, HasNoBigMap t)+      (UnpackedValScope t)   => String -> Text -> Spec unpackNegSpec name encodedHex =   it name $     let encoded = decodeHex (stripOptional0x encodedHex)                   ?: error ("Invalid hex: " <> show encodedHex)-    in runUnpack @t mempty encoded+    in runUnpack @t encoded         `shouldSatisfy` isLeft  -- | Helper for defining tests cases for 'packSpec'.@@ -263,7 +276,7 @@     , (1552564995, "0500838cd2c80b")     ]   where-    convertTimestamps = map . first $ timestampFromSeconds @Int+    convertTimestamps = map . first $ timestampFromSeconds  addressTest :: Spec addressTest = do@@ -274,9 +287,12 @@     , ( "tz1Z1nn9Y7vzyvtf6rAYMPhPNGqMJXw88xGH"       , "050a00000016000092b72c0fa1064331a641131f572e7f2abb9a890b"       )-    , ( "tz1Z1nn9Y7vzyvtf6rAYMPhPNGqMJXw88xGH"-      , "050a00000016000092b72c0fa1064331a641131f572e7f2abb9a890b"+    , ( "tz2EfqCbLmpfv7mNiLcMmhxAwdgHtPTcwR4W"+      , "050a00000016000145b5e7d31bf6612e61ebfa7a6d929ce7800a55a4"       )+    , ( "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r"+      , "050a0000001600025cfa532f50de3e12befc0ad21603835dd7698d35"+      )     , ( "KT1AEseqMV6fk2vtvQCVyA7ZCaxv7cpxtXdB"       , "050a0000001601122d038abd69be91b4b6803f2f098a088e259e7200"       )@@ -289,12 +305,22 @@  keyTest :: Spec keyTest =-  packSpecManual "key" VKey-    [ ( leftToShowPanic $-          parsePublicKey "edpkupH22qrz1sNQt5HSvWfRJFfyJ9dhNbZLptE6GR4JbMoBcACZZH"-      , "050a00000021009a85e0f3f47852869ae667adc3b03a20fa9f324d046174dff6834e7d1fab0e8d"-      )+  packSpecManual "key" allTestMethods VKey+    [ item "edpkupH22qrz1sNQt5HSvWfRJFfyJ9dhNbZLptE6GR4JbMoBcACZZH"+      "050a00000021009a85e0f3f47852869ae667adc3b03a20fa9f324d046174dff6834e7d1fab0e8d"+    , item "edpkuwTWKgQNnhR5v17H2DYHbfcxYepARyrPGbf1tbMoGQAj8Ljr3V"+      "050a0000002100aad3f16293766169f7db278c5e0e9db4fb82ffe1cbcc35258059617dc0fec082"+    , item "sppk7cdA7Afj8MvuBFrP6KsTLfbM5DtH9GwYaRZwCf5tBVCz6UKGQFR"+      "050a000000220103b524d0184276467c848ac13557fb0ff8bec5907960f72683f22af430503edfc1"+    , item "sppk7Ze7NMs6EHF2uB8qq8GrEgJvE9PWYkUijN3LcesafzQuGyniHBD"+      "050a0000002201022c380cd1ff286a0a1a7c3aad6e891d237fa82e2a7cdeec08ccb55e90fdef995f"+    , item "p2pk67K1dwkDFPB63RZU5H3SoMCvmJdKZDZszc7U4FiGKN2YypKdDCB"+      "050a00000022020368afbb09255d849813712108a4144237dc1fdd5bb74e68335f4c68c12c1e5723"+    , item "p2pk68C6tJr7pNLvgBH63K3hBVoztCPCA36zcWhXFUGywQJTjYBfpxk"+      "050a000000220203dcb1916c475902f2b1083212e1b4e6f8ce1531710218c7d34340439f47040e7c"     ]+  where+    item keyStr keyBytes = ( leftToShowPanic $ parsePublicKey keyStr, keyBytes)  unitTest :: Spec unitTest =@@ -304,13 +330,33 @@  signatureTest :: Spec signatureTest =-  packSpecManual "signature" VSignature+  packSpecManual "signature" allTestMethods VSignature+    [ item "edsigtrs8bK7vNfiR4Kd9dWasVa1bAWaQSu2ipnmLGZuwQa8\+           \ktCEMYVKqbWsbJ7zTS8dgYT9tiSUKorWCPFHosL5zPsiDwBQ6vb"+        "050a0000004091ac1e7fd668854fc7a40feec4034e42c06c068cce10622c607fda232d\+        \b34c8cf5d8da83098dd891cd4cb4299b3fa0352ae323ad99b24541e54b91888fdc8201"+    , item "spsig1Ng2bs4PXCbjaFGuojk9K5Pt3CkfbUZyHLLrBxHSmTq\+           \rUUxQggi4yJBit3Ljqnqr61UpdTewTLiu4schSCfZvaRwu412oZ"+        "0x050a0000004080e4e72ffecf72953789625b1125e9f45f432c14e53a01ec68a1e1b77\+        \d60cfe96a97443733ba0f7f42db3a56d7a433df2b4fc0035c05ab92d062f33c5bab0244"+    , item "p2sigRmXDp38VNVaEQH28LYukfLPn8QB5hPEberhvQrrUpRs\+           \cDZJrrApbRh2u46PTVTwKXjxTLKNN9dyLhPQU6U6jWPGxe4d9v"+        "0x050a00000040222222222222222222222222222222222222222222222222222222222\+        \22222222222222222222222222222222222222222222222222222222222222222222222"+    , item "sigrZRt6CTBNtRzjMFQYSZhUm1QcDg5gopVgiRTLMQsgikeR\+           \LmrmsA5vmFqjrnBhofzqvKtc9k5VhTzCMCio5epRvu9no73S"+        "0x050a00000040da632d7f267673fab5a40562778a6890b6ada9665d53d7ff318e3399e\+        \032b3986588dadcf3bf3b549592f7b8ea1365273fbef5f4883c3430ed32e8ae24017be1"+    ]+  where+    item sigStr sigBytes = ( leftToShowPanic $ parseSignature sigStr, sigBytes)++chainIdTest :: Spec+chainIdTest =+  packSpecManual "chain_id" allTestMethods VChainId     [ ( leftToShowPanic $-          parseSignature "edsigtrs8bK7vNfiR4Kd9dWasVa1bAWaQSu2ipnmLGZuwQa8\-                         \ktCEMYVKqbWsbJ7zTS8dgYT9tiSUKorWCPFHosL5zPsiDwBQ6vb"-      , "050a0000004091ac1e7fd668854fc7a40feec4034e42c06c068cce10622c607fda\-        \232db34c8cf5d8da83098dd891cd4cb4299b3fa0352ae323ad99b24541e54b9188\-        \8fdc8201"+          parseChainId "NetXUdfLh6Gm88t"+      , "0x050a00000004458aa837"       )     ] @@ -347,20 +393,34 @@  contractTest :: Spec contractTest = do-  packSpecManual "contract" (VContract @'TUnit) $ parseAddrs+  packSpecManual "simple contract" packTestMethods (addressToVContract @'TUnit) $ parseAddrs     [ "tz1PYgf9fBGLXvwx8ag8sdwjLJzmyGdNiswM"         ~: "050a0000001600002addb327dbca405f07aeef318bba0ec2f714a755"     , "tz1Z1nn9Y7vzyvtf6rAYMPhPNGqMJXw88xGH"         ~: "050a00000016000092b72c0fa1064331a641131f572e7f2abb9a890b"     ] -  packSpecManual "contract" (VContract @('Tc 'CInt)) $ parseAddrs+  packSpecManual "non-unit contract" packTestMethods (addressToVContract @('Tc 'CInt)) $ parseAddrs     [ "KT1AEseqMV6fk2vtvQCVyA7ZCaxv7cpxtXdB"         ~: "0x050a0000001601122d038abd69be91b4b6803f2f098a088e259e7200"     ]++  packSpecManual "contract with entrypoint" packTestMethods (mkEpVContract @('Tc 'CInt)) $ parseEpAddrs+    [ "KT1AEseqMV6fk2vtvQCVyA7ZCaxv7cpxtXdB%"+        ~: "0x050a0000001601122d038abd69be91b4b6803f2f098a088e259e7200"+    , "KT1AEseqMV6fk2vtvQCVyA7ZCaxv7cpxtXdB%abacaba"+        ~: "0x050a0000001d01122d038abd69be91b4b6803f2f098a088e259e720061626163616261"+    , "tz1Z1nn9Y7vzyvtf6rAYMPhPNGqMJXw88xGH%a"+        ~: "0x050a00000017000092b72c0fa1064331a641131f572e7f2abb9a890b61"+    ]   where     parseAddrs = map $ first unsafeParseAddress+    parseEpAddrs = map $ first unsafeParseEpAddress +    mkEpVContract :: forall p. ParameterScope p => EpAddress -> Value ('TContract p)+    mkEpVContract EpAddress{..} =+      VContract eaAddress (SomeEpc def{ epcName = eaEntryPoint })+ pairTest :: Spec pairTest = do   packSpec@@ -404,178 +464,206 @@ instrTest :: Spec instrTest = do   -- Values we compare against are produced with command-  -- ./alphanet.sh client hash data '{ $instrs }' of type 'lambda int int'+  -- ./alphanet.sh client hash data "{ $instrs }" of type 'lambda int int'    parsePackSpec @('Tc 'CInt) @('Tc 'CInt) "instr"-    [ "{ }"+    [ ""        ~: "0x050200000000"-    , "{ PUSH int 1; DROP }"+    , "PUSH int 1; DROP"        ~: "0x0502000000080743035b00010320"-    , "{ DUP; SWAP; DROP }"+    , "DUP; SWAP; DROP"        ~: "0x0502000000060321034c0320"-    , "{ UNIT; DROP }"+    , "UNIT; DUUP; DROP 2"+       ~: "0x050200000016034f020000000b051f02000000020321034c05200002"+    , "UNIT; UNIT; DUUUP; DROP 3"+       ~: "0x05020000001c034f034f020000000f071f0002020000000203210570000305200003"+    , "DIG 0"+       ~: "0x05020000000405700000"+    , "UNIT; DIG 1; DIP { DROP }"+       ~: "0x05020000000f034f05700001051f02000000020320"+    , "DUG 0"+       ~: "0x05020000000405710000"+    , "UNIT; DUG 1; DIP { DROP }"+       ~: "0x05020000000f034f05710001051f02000000020320"+    , "UNIT; DROP"        ~: "0x050200000004034f0320"-    , "{ PUSH int 1; SOME; IF_NONE {} {DROP} }"+    , "UNIT; DROP 1"+       ~: "0x050200000006034f05200001"+    , "DROP 0"+       ~: "0x05020000000405200000"+    , "UNIT; UNIT; UNIT; DROP 3"+      ~: "0x05020000000a034f034f034f05200003"+    , "PUSH int 1; SOME; IF_NONE {} {DROP}"        ~: "0x0502000000160743035b00010346072f020000000002000000020320"-    , "{ PUSH int 1; SOME; IF_SOME {DROP} {} }"+    , "PUSH int 1; SOME; IF_SOME {DROP} {}"        ~: "0x05020000001b0743035b00010346020000000e072f020000000002000000020320"-    , "{ NONE int; DROP }"+    , "NONE int; DROP"        ~: "0x050200000006053e035b0320"-    , "{ PUSH int 1; PAIR; CAR }"+    , "PUSH int 1; PAIR; CAR"        ~: "0x05020000000a0743035b000103420316"-    , "{ LEFT unit; IF_LEFT {} { DROP; PUSH int 1 } }"+    , "LEFT unit; IF_LEFT {} { DROP; PUSH int 1 }"        ~: "0x0502000000180533036c072e0200000000020000000803200743035b0001"-    , "{ RIGHT unit; IF_RIGHT {} { DROP; PUSH int 1 } }"+    , "RIGHT unit; IF_RIGHT {} { DROP; PUSH int 1 }"        ~: "0x05020000001d0544036c0200000014072e020000000803200743035b00010200000000"-    , "{ DUP; NIL int; SWAP; CONS; SIZE; DROP }"+    , "DUP; NIL int; SWAP; CONS; SIZE; DROP"        ~: "0x05020000000e0321053d035b034c031b03450320"-    , "{ NIL int; IF_CONS { DROP; DROP } {} }"+    , "NIL int; IF_CONS { DROP; DROP } {}"        ~: "0x050200000014053d035b072d0200000004032003200200000000"-    , "{ EMPTY_SET int; ITER { DROP } }"+    , "EMPTY_SET int; ITER { DROP }"        ~: "0x05020000000d0524035b055202000000020320"-    , "{ EMPTY_MAP int unit; MAP {}; DROP }"+    , "EMPTY_MAP int unit; MAP {}; DROP"        ~: "0x05020000000f0723035b036c053802000000000320"-    , "{ EMPTY_MAP int unit; PUSH int 1; MEM; DROP }"+    , "EMPTY_MAP int unit; PUSH int 1; MEM; DROP"        ~: "0x0502000000100723035b036c0743035b000103390320"-    , "{ EMPTY_MAP int unit; PUSH int 1; GET; DROP }"+    , "EMPTY_MAP int unit; PUSH int 1; GET; DROP"        ~: "0x0502000000100723035b036c0743035b000103290320"-    , "{ EMPTY_MAP int unit; NONE unit; PUSH int 1; UPDATE; DROP }"+    , "EMPTY_MAP int unit; NONE unit; PUSH int 1; UPDATE; DROP"        ~: "0x0502000000140723035b036c053e036c0743035b000103500320"-    , "{ PUSH bool True; IF {} {} }"+    , "EMPTY_BIG_MAP int unit; PUSH int 1; GET; DROP"+       ~: "0x0502000000100772035b036c0743035b000103290320"+    , "PUSH bool True; IF {} {}"        ~: "0x05020000001207430359030a072c02000000000200000000"-    , "{ PUSH bool True; LOOP { PUSH bool False } }"+    , "PUSH bool True; LOOP { PUSH bool False }"        ~: "0x05020000001307430359030a05340200000006074303590303"-    , "{ PUSH (or int int) (Left 1); LOOP_LEFT { RIGHT int }; DROP }"+    , "PUSH (or int int) (Left 1); LOOP_LEFT { RIGHT int }; DROP"        ~: "0x05020000001907430764035b035b05050001055302000000040544035b0320"-    , "{ LAMBDA int int { PUSH int 1; DROP }; SWAP; EXEC }"+    , "LAMBDA int int { PUSH int 1; DROP }; SWAP; EXEC"        ~: "0x05020000001f093100000011035b035b02000000080743035b0001032000000000034c0326"-    , "{ DIP {} }"+    , "DUP; LAMBDA (pair int int) int { CAR }; SWAP; APPLY; SWAP; EXEC"+       ~: "0x050200000023032109310000000f0765035b035b035b0200000002031600000000034c0373\+          \034c0326"+    , "DIP {}"        ~: "0x050200000007051f0200000000"-    , "{ FAILWITH }"+    , "DIP 1 {}"+       ~: "0x050200000009071f00010200000000"+    , "DIP 0 {}"+       ~: "0x050200000009071f00000200000000"+    , "UNIT; UNIT; DIP 3 { UNIT; DROP }; DROP; DROP"+       ~: "0x050200000015034f034f071f00030200000004034f032003200320"+    , "UNIT; UNIT; DIIIP { UNIT; DROP }; DROP; DROP"+       ~: "0x050200000015034f034f071f00030200000004034f032003200320"+    , "FAILWITH"        ~: "0x0502000000020327"-    , "{ CAST int }"+    , "CAST int"        ~: "0x0502000000040557035b"-    , "{ RENAME }"+    , "RENAME"        ~: "0x0502000000020358"-    , "{ DUP; PACK; UNPACK unit; DROP }"+    , "DUP; PACK; UNPACK unit; DROP"        ~: "0x05020000000a0321030c050d036c0320"-    , "{ PUSH string \"\"; DUP; CONCAT; DROP }"+    , "PUSH string \"\"; DUP; CONCAT; DROP"        ~: "0x05020000000f0743036801000000000321031a0320"-    , "{ NIL string; CONCAT; DROP }"+    , "NIL string; CONCAT; DROP"        ~: "0x050200000008053d0368031a0320"-    , "{ PUSH string \"\"; PUSH nat 1; PUSH nat 2; SLICE; DROP }"+    , "PUSH string \"\"; PUSH nat 1; PUSH nat 2; SLICE; DROP"        ~: "0x050200000019074303680100000000074303620001074303620002036f0320"-    , "{ PUSH int 1; ISNAT; DROP }"+    , "PUSH int 1; ISNAT; DROP"        ~: "0x05020000000a0743035b000103560320"       -- Arithmetic instructions are below-    , "{ PUSH nat 1; INT; DROP }"+    , "PUSH nat 1; INT; DROP"        ~: "0x05020000000a07430362000103300320"       -- SELF cannot appear in lambda       -- CONTRACT - IMPLICIT_ACCOUNT go below-    , "{ NOW; DROP }"+    , "NOW; DROP"       ~: "0x05020000000403400320"-    , "{ AMOUNT; DROP }"+    , "AMOUNT; DROP"       ~: "0x05020000000403130320"-    , "{ BALANCE; DROP }"+    , "BALANCE; DROP"       ~: "0x05020000000403150320"       -- CHECK_SIGNATURE goes below-    , "{ PUSH bytes 0x; SHA256; DROP }"+    , "PUSH bytes 0x; SHA256; DROP"       ~: "0x05020000000d074303690a00000000030f0320"-    , "{ PUSH bytes 0x; SHA512; DROP }"+    , "PUSH bytes 0x; SHA512; DROP"       ~: "0x05020000000d074303690a0000000003100320"-    , "{ PUSH bytes 0x; BLAKE2B; DROP }"+    , "PUSH bytes 0x; BLAKE2B; DROP"       ~: "0x05020000000d074303690a00000000030e0320"       -- HASH_KEY goes below-    , "{ STEPS_TO_QUOTA; DROP }"+    , "STEPS_TO_QUOTA; DROP"       ~: "0x050200000004034a0320"-    , "{ SOURCE; DROP }"+    , "SOURCE; DROP"       ~: "0x05020000000403470320"-    , "{ SENDER; DROP }"+    , "SENDER; DROP"       ~: "0x05020000000403480320"       -- ADDRESS goes below+    , "CHAIN_ID; DROP"+      ~: "0x05020000000403750320"     ]    parsePackSpec @'TUnit @'TUnit "arith instr"-    [ "{ PUSH int 1; PUSH int 2; ADD; DROP }"+    [ "PUSH int 1; PUSH int 2; ADD; DROP"        ~: "0x0502000000100743035b00010743035b000203120320"-    , "{ PUSH int 1; PUSH int 2; SUB; DROP }"+    , "PUSH int 1; PUSH int 2; SUB; DROP"        ~: "0x0502000000100743035b00010743035b0002034b0320"-    , "{ PUSH int 1; PUSH int 2; MUL; DROP }"+    , "PUSH int 1; PUSH int 2; MUL; DROP"        ~: "0x0502000000100743035b00010743035b0002033a0320"-    , "{ PUSH int 1; PUSH int 2; EDIV; DROP }"+    , "PUSH int 1; PUSH int 2; EDIV; DROP"        ~: "0x0502000000100743035b00010743035b000203220320"-    , "{ PUSH int 1; ABS; DROP }"+    , "PUSH int 1; ABS; DROP"        ~: "0x05020000000a0743035b000103110320"-    , "{ PUSH int 1; NEG; DROP }"+    , "PUSH int 1; NEG @kek; DROP"        ~: "0x05020000000a0743035b0001033b0320"-    , "{ PUSH nat 1; PUSH nat 2; LSL; DROP }"+    , "PUSH nat 1; PUSH nat 2; LSL; DROP"        ~: "0x05020000001007430362000107430362000203350320"-    , "{ PUSH nat 1; PUSH nat 2; LSR; DROP }"+    , "PUSH nat 1; PUSH nat 2; LSR; DROP"        ~: "0x05020000001007430362000107430362000203360320"-    , "{ PUSH nat 1; PUSH nat 2; OR; DROP }"+    , "PUSH nat 1; PUSH nat 2; OR; DROP"        ~: "0x05020000001007430362000107430362000203410320"-    , "{ PUSH nat 1; PUSH nat 2; XOR; DROP }"+    , "PUSH nat 1; PUSH nat 2; XOR; DROP"        ~: "0x05020000001007430362000107430362000203510320"-    , "{ PUSH int 1; NOT; DROP }"+    , "PUSH int 1; NOT; DROP"        ~: "0x05020000000a0743035b0001033f0320"-    , "{ PUSH nat 1; PUSH nat 2; COMPARE; DROP }"+    , "PUSH nat 1; PUSH nat 2; COMPARE; DROP"        ~: "0x05020000001007430362000107430362000203190320"-    , "{ PUSH int 1; EQ; DROP }"+    , "PUSH int 1; EQ; DROP"        ~: "0x05020000000a0743035b000103250320"-    , "{ PUSH int 1; NEQ; DROP }"+    , "PUSH int 1; NEQ; DROP"        ~: "0x05020000000a0743035b0001033c0320"-    , "{ PUSH int 1; LT; DROP }"+    , "PUSH int 1; LT; DROP"        ~: "0x05020000000a0743035b000103370320"-    , "{ PUSH int 1; GT; DROP }"+    , "PUSH int 1; GT; DROP"        ~: "0x05020000000a0743035b0001032a0320"-    , "{ PUSH int 1; LE; DROP }"+    , "PUSH int 1; LE; DROP"        ~: "0x05020000000a0743035b000103320320"-    , "{ PUSH int 1; GE; DROP }"+    , "PUSH int 1; GE; DROP"        ~: "0x05020000000a0743035b000103280320"     ]    parsePackSpec @('Tc 'CAddress) @'TUnit "instrs address-related"-    [ "{ CONTRACT unit; DROP; PUSH unit Unit }"+    [ "CONTRACT unit; DROP; PUSH unit Unit"        ~: "0x05020000000c0555036c03200743036c030b"     ]    parsePackSpec @('TContract 'TUnit) @'TUnit "instrs contract-related"-    [ "{ PUSH mutez 5; PUSH unit Unit; TRANSFER_TOKENS; DROP; PUSH unit Unit }"+    [ "PUSH mutez 5; PUSH unit Unit; TRANSFER_TOKENS; DROP; PUSH unit Unit"        ~: "0x0502000000160743036a00050743036c030b034d03200743036c030b"-    , "{ ADDRESS; DROP; PUSH unit Unit }"+    , "ADDRESS; DROP; PUSH unit Unit"        ~: "0x05020000000a035403200743036c030b"     ]    parsePackSpec @('Tc 'CKeyHash) @'TUnit "instrs key-hash-related"-    [ "{ SOME; SET_DELEGATE; DROP; PUSH unit Unit }"+    [ "SOME; SET_DELEGATE; DROP; PUSH unit Unit"        ~: "0x05020000000c0346034e03200743036c030b"-    , "{ DUP; DIP{ SOME; DIP{ PUSH mutez 5; PUSH bool True } }; \-        \CREATE_ACCOUNT; DROP; DROP; PUSH unit Unit \-      \}"-       ~: "0x05020000002a0321051f02000000150346051f020000000c0743036a00\-          \0507430359030a031c032003200743036c030b"-    , "{ DUP; DIP{ SOME; DIP{ PUSH unit Unit; PUSH mutez 5; PUSH bool True; DUP } }; \+    , "SOME; DIP{ PUSH unit Unit; PUSH mutez 5; }; \        \ CREATE_CONTRACT{ \        \   parameter unit; \        \   storage unit; \        \   code { DROP; UNIT; NIL operation; PAIR } \        \  }; \        \ DROP; DROP; PUSH unit Unit \-       \}"-       ~: "0x0502000000500321051f020000001d0346051f02000000140743036c030\-          \b0743036a000507430359030a0321051d02000000190500036c0501036c050\-          \2020000000a0320034f053d036d0342032003200743036c030b"-    , "{ IMPLICIT_ACCOUNT; DROP; PUSH unit Unit }"+       \"+       ~: "0x05020000003f0346051f020000000c0743036c030b0743036a0005051d020000\+          \00190500036c0501036c0502020000000a0320034f053d036d0342032003200743\+          \036c030b"+    , "IMPLICIT_ACCOUNT; DROP; PUSH unit Unit"        ~: "0x05020000000a031e03200743036c030b"     ]    parsePackSpec @'TKey @('Tc 'CKeyHash) "instrs public-key-related"-    [ "{ HASH_KEY }"+    [ "HASH_KEY"        ~: "0x050200000002032b"     ]    parsePackSpec @('TPair 'TSignature 'TKey) @('Tc 'CBool) "instrs public-key-related"-    [ "{ DIP{ PUSH bytes 0x }; DUP; DIP {CAR}; CDR; CHECK_SIGNATURE }"+    [ "DIP{ PUSH bytes 0x }; DUP; DIP {CAR}; CDR; CHECK_SIGNATURE"        ~: "0x05020000001f051f0200000009074303690a000000000321051f020000\           \0002031603170318"     ]@@ -611,6 +699,8 @@         ~: "0x050200000015093100000009036c036c0200000000000000000320"     , lambdaWrap "signature"         ~: "0x050200000015093100000009036703670200000000000000000320"+    , lambdaWrap "chain_id"+        ~: "0x050200000015093100000009037403740200000000000000000320"     , lambdaWrap "option unit"         ~: "0x05020000001909310000000d0563036c0563036c0200000000000000000320"     , lambdaWrap "set int"@@ -631,7 +721,7 @@         ~: "0x05020000001d0931000000110761035b036c0761035b036c0200000000000000000320"     ]   where-    lambdaWrap ty = "{ LAMBDA " <> ty <> " " <> ty <> " {}; DROP }"+    lambdaWrap ty = "LAMBDA " <> ty <> " " <> ty <> " {}; DROP"  unpackNegTest :: Spec unpackNegTest = do@@ -658,3 +748,37 @@       "0x0502000000060743035b0005"  -- {PUSH int 5}     unpackNegSpec @('TLambda 'TUnit 'TKey) "Lambda empty output stack size"       "0x0502000000020320"  -- {DROP}++readableUnpackTest :: Spec+readableUnpackTest = do+  describe "Unpack crypto primitives from Readable representation" $ do+    -- ./tezos-client hash data '"tz1akcPmG1Kyz2jXpS4RvVJ8uWr7tsiT9i6A"' of type 'string'+    unpackReadableSpec @('Tc 'CAddress) "Unpack readable address"+      "0x050100000024747a31666173774354446369527a45346f4a396a6e32566\+      \d3264766a6579413966557a55"+    -- ./tezos-client hash data '"edpktezaD1wnUa5pT2pvj1JGHNey18WGhPc9fk9bbppD33KNQ2vH8R"'+    -- of type 'string'+    unpackReadableSpec @'TKey "Unpack readable public key"+      "0x0501000000366564706b74657a614431776e55613570543270766a314a4\+      \7484e65793138574768506339666b39626270704433334b4e513276483852"+      -- ./tezos-client-babylonnet hash data '"edsigtqgdc2JLMDcERHo61Y76mrxqCeqDE5YhHiBo\+      -- \VtwjhFKahAkCT7RCZKQLhLJ3yJbrVyJCkVGEoiHbyKytHW846dDC4P121K"' of type 'string'+    unpackReadableSpec @'TSignature "Unpack readable signature"+      "0x05010000006365647369677471676463324a4c4d44634552486f36315937\+      \366d72787143657144453559684869426f5674776a68464b6168416b435437\+      \52435a4b514c684c4a33794a627256794a436b5647456f694862794b797448\+      \5738343664444334503132314b"++    -- ./tezos-client-babylonnet hash data '"NetXUdfLh6Gm88t"' of type string+    unpackReadableSpec @'TChainId "Unpack readable chain_id"+      "0x05010000000f4e6574585564664c6836476d383874"++  where+    unpackReadableSpec+      :: forall t. (UnpackedValScope t)+      => String -> Text -> Spec+    unpackReadableSpec name encodedHex =+      it name $+        let encoded = decodeHex (stripOptional0x encodedHex)+                     ?: error ("Invalid hex: " <> show encodedHex)+        in runUnpack @t encoded `shouldSatisfy` isRight
test/Test/Tezos/Address.hs view
@@ -31,11 +31,20 @@   where     sampleAddresses =       [ "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU"+      , "tz1Wit2PqodvPeuRRhdQXmkrtU8e8bRYZecd"+      , "tz2EfqCbLmpfv7mNiLcMmhxAwdgHtPTcwR4W"+      , "tz2Darj3LyQzekU98ZK8diHvuyn1YYjcHpc6"+      , "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r"+      , "tz3NExpXn9aPNZPorRE4SdjJ2RGrfbJgMAaV"       , "KT1G4hcQj2STN86GwC1XAkPtwPPhgfPKuE45"+      , "KT1QbdJ7M7uAQZwLpvzerUyk7LYkJWDL7eDh"       ]     invalidAddresses =       [ ""       , "1"+      -- These are slightly modified versions of some valid addresses above.       , "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUZU"+      , "tz2darj3LyQzekU98ZK8diHvuyn1YYjcHpc6"+      , "tz3UoffC8FG7zfpmvmjUmUeAaHvzdcUvAj6r"       , "KT1G4hcQj2STN86GwC1XAkPtwPPhgfPKuE46"       ]
+ test/Test/Tezos/Core.hs view
@@ -0,0 +1,76 @@+module Test.Tezos.Core+  ( test_ParseTimestamp+  , test_TimestampQuote+  , test_ChainId_roundtrip+  , test_Parse_ChainId+  ) where++import Test.HUnit ((@?=))+import Test.Tasty (TestTree)+import Test.Tasty.HUnit (testCase)+import Test.Util.QuickCheck (ShowThroughBuild(..), aesonRoundtrip, roundtripTestSTB)+import Test.Hspec (shouldBe, shouldSatisfy)+import Test.Tasty (testGroup)++import Tezos.Core++----------------------------------------------------------------------------+-- Timestamp+----------------------------------------------------------------------------++test_ParseTimestamp :: [TestTree]+test_ParseTimestamp =+  [ testCase "Correctly parse valid inputs" $ do+      parseTimestamp "2018-08-08T00:00:00Z" `shouldBe` Just (Timestamp 1533686400)+      parseTimestamp "2018-08-08 00:00:00Z" `shouldBe` Just (Timestamp 1533686400)++  , testCase "Does not parse leading and trailing spaces" $ do+      parseTimestamp " 2018-08-08T00:00:00Z" `shouldSatisfy` isNothing+      parseTimestamp "2018-08-08T00:00:00Z " `shouldSatisfy` isNothing+      parseTimestamp " 2018-08-08T00:00:00Z " `shouldSatisfy` isNothing++  , testCase "Does not parse with multiple separating spaces" $ do+      parseTimestamp "2018-08-08  00:00:00Z" `shouldSatisfy` isNothing+      parseTimestamp "2018-08-08   00:00:00Z" `shouldSatisfy` isNothing+  ]++test_TimestampQuote :: [TestTree]+test_TimestampQuote =+  [ testCase "Quoter works in simple case" $+      [timestampQuote|2019-07-26T12:09:12Z|]+        @?= timestampFromSeconds 1564142952++  , testCase "Quoter works with surrounding spaces" $+      [timestampQuote| 2019-07-26T12:09:12Z |]+        @?= timestampFromSeconds 1564142952+  ]++----------------------------------------------------------------------------+-- ChainId+----------------------------------------------------------------------------++test_ChainId_roundtrip :: [TestTree]+test_ChainId_roundtrip =+    [ testGroup "parse . format ≡ pure"+      [ roundtripTestSTB formatChainId parseChainId ]+    , testGroup "JSON encoding/deconding"+      [ aesonRoundtrip @ChainId ]+    ]++test_Parse_ChainId :: [TestTree]+test_Parse_ChainId =+  [ testCase "Successfully parses valid sample data" $+    forM_ sampleChainIds (\a -> bimap STB STB (parseChainId a) `shouldSatisfy` isRight)+  , testCase "Fails to parse invalid data" $ do+    forM_ invalidChainIds (\a -> bimap STB STB (parseChainId a) `shouldSatisfy` isLeft)+  ]+  where+    sampleChainIds =+      [ "NetXUdfLh6Gm88t"+      ]+    invalidChainIds =+      [ ""+      , "1"+      , "NetXUdfLh6Gm88r"  -- last char changed+      , "5uYAAtMU9Bi2Qe"  -- valid base58, wrong size+      ]
test/Test/Tezos/Crypto.hs view
@@ -3,11 +3,10 @@ module Test.Tezos.Crypto   ( test_Roundtrip   , test_Signing-  , test_Bytes_Hashing   , unit_Key_Hashing   ) where -import Fmt (fmt, hexF, pretty)+import Fmt (pretty) import Test.Hspec (Expectation, shouldSatisfy) import Test.HUnit (Assertion, (@?=)) import Test.Tasty (TestTree, testGroup)@@ -21,7 +20,6 @@ test_Roundtrip =   [ testGroup "parse . format ≡ pure"     [ roundtripTestSTB formatPublicKey parsePublicKey-    , roundtripTestSTB formatSecretKey parseSecretKey     , roundtripTestSTB formatSignature parseSignature     , roundtripTestSTB formatKeyHash parseKeyHash     ]@@ -43,21 +41,45 @@         [ testCase "Successfully parses valid sample data" $           mapM_ (parsePublicKeySample . sdPublicKey) sampleSignatures         , testCase "Fails to parse invalid data" $ do+            parsePublicKeyInvalid ""             parsePublicKeyInvalid "aaa"+             parsePublicKeyInvalid               "edpkuwTWKgQNnhR5v17H2DYHbfcxYepARyrPGbf1tbMoGQAj8Ljr3v"             parsePublicKeyInvalid               "edsigtrs8bK7vNfiR4Kd9dWasVa1bAWaQSu2ipnmLGZuwQa8ktCEMYVKqbWsbJ7zTS8dgYT9tiSUKorWCPFHosL5zPsiDwBQ6vb"++            parsePublicKeyInvalid+              "sppk7Ze7NMs6EHF2uB8qq8GrEgJvE9PWYkUijN3LcesafzQuGyniHBd"+            parsePublicKeyInvalid+              "spsig1Ng2bs4PXCbjaFGuojk9K5Pt3CkfbUZyHLLrBxHSmTqrUUxQggi4yJBit3Ljqnqr61UpdTewTLiu4schSCfZvaRwu412oZ"++            parsePublicKeyInvalid+              "p2pk68C6tJr7pNLvgBH63K3hBVoztCPCA36zcWhXFUGywQJTjYbfpxk"+            parsePublicKeyInvalid+              "p2sigRmXDp38VNVaEQH28LYukfLPn8QB5hPEberhvQrrUpRscDZJrrApbRh2u46PTVTwKXjxTLKNN9dyLhPQU6U6jWPGxe4d9v"         ]       , testGroup "parseSignature"         [ testCase "Successfully parses valid sample data" $           mapM_ (parseSignatureSample . sdSignature) sampleSignatures         , testCase "Fails to parse invalid data" $ do+            parseSignatureInvalid ""             parseSignatureInvalid "bbb"+             parseSignatureInvalid               "edpkuwTWKgQNnhR5v17H2DYHbfcxYepARyrPGbf1tbMoGQAj8Ljr3V"             parseSignatureInvalid               "edsigtrs8bK7vNfiR4Kd9dWasVa1bAWaQSu2ipnmLGZuwQa8ktCEMYVKqbWsbJ7zTS8dgYT9tiSUKorWCPFHosL5zPsiDwBQ6vB"++            parseSignatureInvalid+              "sppk7cdA7Afj8MvuBFrP6KsTLfbM5DtH9GwYaRZwCf5tBVCz6UKGQFR"+            parseSignatureInvalid+              "spsig1Ng2bs4PXCbjaFGuojk9K5Pt3ckfbUZyHLLrBxHSmTqrUUxQggi4yJBit3Ljqnqr61UpdTewTLiu4schSCfZvaRwu412oZ"++            parseSignatureInvalid+              "p2pk68C6tJr7pNLvgBH63K3hBVoztCPCA36zcWhXFUGywQJTjYBfpxk"+            parseSignatureInvalid+              "p2sigRmXDp38VNVaEQH28LYukfLPn8QB5hPEberhvQrrUpRscDZJrrApbrh2u46PTVTwKXjxTLKNN9dyLhPQU6U6jWPGxe4d9v"         ]       ]   , testCase "checkSignature" $ mapM_ checkSignatureSample sampleSignatures@@ -92,6 +114,37 @@     , sdValid = False     }   ]+  <>+  [ SignatureData+    { sdPublicKey = "sppk7cdA7Afj8MvuBFrP6KsTLfbM5DtH9GwYaRZwCf5tBVCz6UKGQFR"+    , sdBytes = "\0"+    , sdSignature = "spsig1Ng2bs4PXCbjaFGuojk9K5Pt3CkfbUZyHLLrBxHSmTqrUUxQggi4yJBit3Ljqnqr61UpdTewTLiu4schSCfZvaRwu412oZ"+    -- TODO (#18): should be valid, but crypto is not implemented yet.+    , sdValid = False+    }+  , SignatureData+    { sdPublicKey = "sppk7Ze7NMs6EHF2uB8qq8GrEgJvE9PWYkUijN3LcesafzQuGyniHBD"+    , sdBytes = "\0\0"+    , sdSignature = "spsig1aP7D9oheiraNuM1NgziMPSPKS1F9kSWyFqkE8WigaeU5Uzb3LwY34F7Y7RsF6sY5ZfUda1NWdrC5V4KEfm9jeU1eniHmy"+    -- TODO (#18): should be valid, but crypto is not implemented yet.+    , sdValid = False+    }+  , SignatureData+    { sdPublicKey = "sppk7Ze7NMs6EHF2uB8qq8GrEgJvE9PWYkUijN3LcesafzQuGyniHBD"+    , sdBytes = "kot"+    , sdSignature = "spsig1PJ9LG9ovbpVJ3CucFWL7iBaQZjqEWMvppgLjYiiSwzcxpuUqHr2BUVZDUwkmZKzMNDWJdgtyhYiicz197TbhS4LPpnxDY"+    , sdValid = False+    }+  ]+  <>+  -- TODO (#18): add valid samples for P256+  [ SignatureData+    { sdPublicKey = "p2pk68C6tJr7pNLvgBH63K3hBVoztCPCA36zcWhXFUGywQJTjYBfpxk"+    , sdBytes = "kot"+    , sdSignature = "p2sigRmXDp38VNVaEQH28LYukfLPn8QB5hPEberhvQrrUpRscDZJrrApbRh2u46PTVTwKXjxTLKNN9dyLhPQU6U6jWPGxe4d9v"+    , sdValid = False+    }+  ]  parsePublicKeySample :: Text -> Expectation parsePublicKeySample publicKeyText =@@ -117,46 +170,6 @@     signature = partialParse parseSignature (sdSignature sd)  ------------------------------------------------------------------------------- Hashing-------------------------------------------------------------------------------test_Bytes_Hashing :: [TestTree]-test_Bytes_Hashing =-  [ testGroup "blake2b" $ hashingTest blake2b blake2bHashes-  , testGroup "sha256" $ hashingTest sha256 sha256Hashes-  , testGroup "sha512" $ hashingTest sha512 sha512Hashes-  ]---- These values have been computed using the following contract:-{--parameter string;-storage bytes;-code { CDR; SHA512; # replace with desired function-       NIL operation; PAIR;};---}--blake2bHashes, sha256Hashes, sha512Hashes :: [(ByteString, Text)]-blake2bHashes =-  [ ("\0", "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314")  -- 0x00-  , ("\0\0", "9ee6dfb61a2fb903df487c401663825643bb825d41695e63df8af6162ab145a6")  -- 0x0000-  ]-sha256Hashes =-  [ ("\0", "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d")  -- 0x00-  , ("\0\0", "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7")  -- 0x0000-  ]-sha512Hashes =-  [ ("\0", "b8244d028981d693af7b456af8efa4cad63d282e19ff14942c246e50d9351d22704a802a71c3580b6370de4ceb293c324a8423342557d4e5c38438f0e36910ee")  -- 0x00-  , ("#", "d369286ac86b60fa920f6464d26becacd9f4c8bd885b783407cdcaa74fafd45a8b56b364b63f6256c3ceef26278a1c7799d4243a8149b5ede5ce1d890b5c7236")  -- 0x23-  ]--hashingTest :: (ByteString -> ByteString) -> [(ByteString, Text)] -> [TestTree]-hashingTest hashFunc pairs = do-  flip map pairs $ \(bs, bsHashHex) -> do-    testCase ("correctly computes hash of 0x" <> fmt (hexF bs)) $-      fmt (hexF (hashFunc bs)) @?= bsHashHex------------------------------------------------------------------------------ -- Key hashing ---------------------------------------------------------------------------- @@ -165,11 +178,23 @@  sampleKeyHashes :: [(Text, Text)] sampleKeyHashes =-  [ ("edpkupH22qrz1sNQt5HSvWfRJFfyJ9dhNbZLptE6GR4JbMoBcACZZH"+  [ ( "edpkupH22qrz1sNQt5HSvWfRJFfyJ9dhNbZLptE6GR4JbMoBcACZZH"     , "tz1NaZzLvdDBLfV2LWC6F4SJfNV2jHdZJXkJ"     )-  , ("edpkuwTWKgQNnhR5v17H2DYHbfcxYepARyrPGbf1tbMoGQAj8Ljr3V"+  , ( "edpkuwTWKgQNnhR5v17H2DYHbfcxYepARyrPGbf1tbMoGQAj8Ljr3V"     , "tz1Yz3VPaCNB5FjhdEVnSoN8Xv3ZM8g2LYhw"+    )+  , ( "sppk7cdA7Afj8MvuBFrP6KsTLfbM5DtH9GwYaRZwCf5tBVCz6UKGQFR"+    , "tz2EfqCbLmpfv7mNiLcMmhxAwdgHtPTcwR4W"+    )+  , ( "sppk7Ze7NMs6EHF2uB8qq8GrEgJvE9PWYkUijN3LcesafzQuGyniHBD"+    , "tz2Darj3LyQzekU98ZK8diHvuyn1YYjcHpc6"+    )+  , ( "p2pk67K1dwkDFPB63RZU5H3SoMCvmJdKZDZszc7U4FiGKN2YypKdDCB"+    , "tz3S7wbUwQV581kroR81fYbgDBskFicZ6czW"+    )+  , ( "p2pk68C6tJr7pNLvgBH63K3hBVoztCPCA36zcWhXFUGywQJTjYBfpxk"+    , "tz3QEbmdCdsMcnUo2rNjXdbKwg5tyack3goN"     )   ] 
+ test/Test/Tezos/Crypto/Hash.hs view
@@ -0,0 +1,48 @@+-- | Tests for 'Tezos.Crypto.Hash'.++module Test.Tezos.Crypto.Hash+  ( test_Bytes_Hashing+  ) where++import Fmt (fmt, hexF)+import Test.HUnit ((@?=))+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (testCase)++import Tezos.Crypto.Hash++test_Bytes_Hashing :: [TestTree]+test_Bytes_Hashing =+  [ testGroup "blake2b" $ hashingTest blake2b blake2bHashes+  , testGroup "sha256" $ hashingTest sha256 sha256Hashes+  , testGroup "sha512" $ hashingTest sha512 sha512Hashes+  ]++-- These values have been computed using the following contract:+{-+parameter string;+storage bytes;+code { CDR; SHA512; # replace with desired function+       NIL operation; PAIR;};++-}++blake2bHashes, sha256Hashes, sha512Hashes :: [(ByteString, Text)]+blake2bHashes =+  [ ("\0", "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314")  -- 0x00+  , ("\0\0", "9ee6dfb61a2fb903df487c401663825643bb825d41695e63df8af6162ab145a6")  -- 0x0000+  ]+sha256Hashes =+  [ ("\0", "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d")  -- 0x00+  , ("\0\0", "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7")  -- 0x0000+  ]+sha512Hashes =+  [ ("\0", "b8244d028981d693af7b456af8efa4cad63d282e19ff14942c246e50d9351d22704a802a71c3580b6370de4ceb293c324a8423342557d4e5c38438f0e36910ee")  -- 0x00+  , ("#", "d369286ac86b60fa920f6464d26becacd9f4c8bd885b783407cdcaa74fafd45a8b56b364b63f6256c3ceef26278a1c7799d4243a8149b5ede5ce1d890b5c7236")  -- 0x23+  ]++hashingTest :: (ByteString -> ByteString) -> [(ByteString, Text)] -> [TestTree]+hashingTest hashFunc pairs = do+  flip map pairs $ \(bs, bsHashHex) -> do+    testCase ("correctly computes hash of 0x" <> fmt (hexF bs)) $+      fmt (hexF (hashFunc bs)) @?= bsHashHex
test/Test/Typecheck.hs view
@@ -3,12 +3,12 @@ module Test.Typecheck   ( unit_Good_contracts   , unit_Bad_contracts-  , test_OriginatedContracts   , test_srcPosition   , unit_Unreachable_code   , test_Roundtrip   , test_StackRef   , test_TCTypeError_display+  , prop_ValueSeq_as_list   ) where  import Data.Default (def)@@ -20,7 +20,8 @@ import Test.Hspec (expectationFailure) import Test.Hspec.Expectations (Expectation) import Test.HUnit (Assertion, assertFailure, (@?=))-import Test.QuickCheck (Arbitrary, property, total, within)+import Test.QuickCheck (Arbitrary, Property, arbitrary, forAll, property, total, within)+import Test.QuickCheck.Instances.Semigroup () import Test.Tasty (TestTree, testGroup) import Test.Tasty.HUnit (testCase) import Test.Tasty.QuickCheck (testProperty)@@ -31,9 +32,9 @@ import Michelson.Test.Import (ImportContractError(..), readContract) import Michelson.TypeCheck import qualified Michelson.Typed as T-import Michelson.Untyped (CT(..), T(..), Type(..), noAnn)+import Michelson.Untyped (Type(..), noAnn) import qualified Michelson.Untyped as Un-import Tezos.Address (Address, unsafeParseAddress)+import Tezos.Address (ContractHash) import Tezos.Core (Timestamp) import Util.IO (readFileUtf8) @@ -45,27 +46,6 @@ unit_Bad_contracts :: Assertion unit_Bad_contracts = mapM_ (\f -> checkFile [] False f (const pass)) =<< getIllTypedContracts -test_OriginatedContracts :: [TestTree]-test_OriginatedContracts =-  [ testCase "Successfully typechecked PUSH contract considering originated contracts" $ do-    checkFile' [(cAddr, tPair intP intQ)] True pushContrFile-    checkFile' [(cAddr, tPair int intQ)] True pushContrFile-    checkFile' [(cAddr, tPair int int)] True pushContrFile-  , testCase "Report an error on PUSH contract because of mismatched types" $ do-    checkFile' [(cAddr, tPair intP intP)] False pushContrFile-    checkFile' [(cAddr, tPair intQ intQ)] False pushContrFile-    checkFile' [(cAddr, tPair string intQ)] False pushContrFile-  ]-  where-    checkFile' a b f = checkFile a b f (const pass)-    pushContrFile = "contracts/ill-typed/push_contract.tz"-    tPair t1 t2 = Type (TPair noAnn noAnn t1 t2) noAnn-    intP = Type (Tc CInt) "p"-    intQ = Type (Tc CInt) "q"-    int = Type (Tc CInt) noAnn-    string = Type (Tc CString) noAnn-    cAddr = unsafeParseAddress "KT1WsLzQ61xtMNJHfwgCHh2RnALGgFAzeSx9"- pattern IsSrcPos :: Word -> Word -> InstrCallStack pattern IsSrcPos l c <- InstrCallStack [] (SrcPos (Pos l) (Pos c)) @@ -86,8 +66,11 @@        checkIllFile "contracts/ill-typed/macro_in_let_fail.mtz" $ \case           TCFailedOnInstr (Un.COMPARE _) _ _ (InstrCallStack [LetName "cmpLet"] (SrcPos (Pos 3) (Pos 6)))-                                              (Just (UnsupportedTypes _)) -> True+                                              (Just (TypeEqError _ _)) -> True           _ -> False+      checkIllFile "contracts/ill-typed/compare_annotation_mismatch.tz" $ \case+          TCFailedOnInstr (Un.COMPARE _) _ _ _ (Just (AnnError _)) -> True+          _ -> False   ]   where     unexpected f e =@@ -96,7 +79,8 @@       \e -> if check e then pass else unexpected file e  checkFile-  :: [(Address, Type)]+  :: HasCallStack+  => [(ContractHash, Type)]   -> Bool   -> FilePath   -> (TCError -> Expectation)@@ -142,7 +126,7 @@     testProperty (show $ typeRep (Proxy @a)) $       property $ \(val :: T.Value (T.ToT a)) ->         let uval = T.untypeValue val-            runTC = runTypeCheckTest . usingReaderT (def @InstrCallStack)+            runTC = runTypeCheckIsolated . usingReaderT (def @InstrCallStack)         in case runTC $ typeVerifyValue uval of             Right got -> got @?= val             Left err -> expectationFailure $@@ -174,7 +158,7 @@   ]   where     printStRef i = Un.EXT . Un.UPRINT $ Un.PrintComment [Right (Un.StackRef i)]-    stackEl = (sing @'T.TUnit, T.NStar, noAnn)+    stackEl = (sing @'T.TUnit, T.starNotes, noAnn)  test_TCTypeError_display :: [TestTree] test_TCTypeError_display =@@ -194,7 +178,16 @@       build (UnsupportedTypes [T.TUnit])       @?= "Unsupported types: [unit]" -  , testCase "Unknown type" $-      build (UnknownType T.TUnit)-      @?= "Unknown type `unit`"+  , testCase "InvalidValueType" $+      build (InvalidValueType T.TUnit)+      @?= "Value type is never a valid `unit`"   ]++prop_ValueSeq_as_list :: Property+prop_ValueSeq_as_list =+  forAll @(NonEmpty Integer) arbitrary $ \l ->+  let+    untypedValue = Un.ValueSeq $ Un.ValueInt <$> l+    typedValue = T.VList $ (T.VC . T.CvInt) <$> toList l+    runTypeCheckInstr = runTypeCheckIsolated . usingReaderT def+  in runTypeCheckInstr (typeVerifyValue untypedValue) == Right typedValue
test/Test/Util/Contracts.hs view
@@ -3,13 +3,15 @@ module Test.Util.Contracts        ( getIllTypedContracts        , getWellTypedContracts+       , getUnparsableContracts        , getWellTypedMichelsonContracts        , getWellTypedMorleyContracts+       , getContractsWithReferences        ) where  import Data.List (isSuffixOf) import System.Directory (listDirectory)-import System.FilePath ((</>))+import System.FilePath (addExtension, (</>))  getIllTypedContracts :: IO [FilePath] getIllTypedContracts =@@ -19,8 +21,14 @@ getWellTypedContracts :: IO [FilePath] getWellTypedContracts = getWellTypedMichelsonContracts <> getWellTypedMorleyContracts +getUnparsableContracts :: IO [FilePath]+getUnparsableContracts =+  concatMapM (flip getContractsWithExtension "contracts/unparsable")+  [".tz", ".mtz"]+ getWellTypedMichelsonContracts :: IO [FilePath]-getWellTypedMichelsonContracts = concatMapM (getContractsWithExtension ".tz") wellTypedContractDirs+getWellTypedMichelsonContracts =+  concatMapM (getContractsWithExtension ".tz") wellTypedContractDirs  getWellTypedMorleyContracts :: IO [FilePath] getWellTypedMorleyContracts = concatMapM (getContractsWithExtension ".mtz") wellTypedContractDirs@@ -35,4 +43,18 @@       | otherwise = Nothing  wellTypedContractDirs :: [FilePath]-wellTypedContractDirs = ["contracts", "contracts/A1", "contracts/tezos_examples"]+wellTypedContractDirs =+  "contracts" :+  map (("contracts" </> "tezos_examples") </>)+    [ "attic"+    , "macros"+    , "mini_scenarios"+    , "opcodes"+    ]++getContractsWithReferences :: String -> FilePath -> String -> IO [(FilePath, FilePath)]+getContractsWithReferences ext fp refExt =+  fmap attachPrettyPath <$> getContractsWithExtension ext fp+  where+    attachPrettyPath :: FilePath -> (FilePath, FilePath)+    attachPrettyPath src = (src, addExtension src  refExt)
+ test/Test/Util/HUnit.hs view
@@ -0,0 +1,14 @@+-- | Helpers for HUnit.++module Test.Util.HUnit+  ( assertEqualBuild+  ) where++import Test.HUnit (Assertion, assertEqual)+import Test.Util.QuickCheck (ShowThroughBuild(..))++assertEqualBuild+  :: (HasCallStack, Eq a, Show (ShowThroughBuild a))+  => String -> a -> a -> Assertion+assertEqualBuild desc a b =+  assertEqual desc (STB a) (STB b)