cleveland 0.2.0 → 0.2.1
raw patch · 59 files changed
+2965/−2201 lines, 59 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Test.Cleveland: OriginateData :: Alias -> Mutez -> st -> Contract param st vd -> OriginateData param st vd
- Test.Cleveland: UntypedOriginateData :: Alias -> Mutez -> Value -> Contract -> UntypedOriginateData
- Test.Cleveland: [IsRPC] :: forall v. (SingI (ToT v), IsoValue (AsRPC v), HasRPCRepr v) => AsRPC v -> MaybeRPC v
- Test.Cleveland: [NotRPC] :: forall v. IsoValue v => v -> MaybeRPC v
- Test.Cleveland: [odBalance] :: OriginateData param st vd -> Mutez
- Test.Cleveland: [odContract] :: OriginateData param st vd -> Contract param st vd
- Test.Cleveland: [odName] :: OriginateData param st vd -> Alias
- Test.Cleveland: [odStorage] :: OriginateData param st vd -> st
- Test.Cleveland: [uodBalance] :: UntypedOriginateData -> Mutez
- Test.Cleveland: [uodContract] :: UntypedOriginateData -> Contract
- Test.Cleveland: [uodName] :: UntypedOriginateData -> Alias
- Test.Cleveland: [uodStorage] :: UntypedOriginateData -> Value
- Test.Cleveland: call :: forall param vd addr m epRef epArg. (HasCallStack, MonadOps m, ToTAddress param vd addr, HasEntrypointArg param epRef epArg, IsoValue epArg, Typeable epArg) => addr -> epRef -> epArg -> m ()
- Test.Cleveland: data MaybeRPC v
- Test.Cleveland: data OriginateData param st vd
- Test.Cleveland: data Scenario m
- Test.Cleveland: data UntypedOriginateData
- Test.Cleveland: originateLarge :: forall param st vd m caps. (HasCallStack, MonadCleveland caps m) => OriginateData param st vd -> m (ContractHandle param st vd)
- Test.Cleveland: originateLargeSimple :: forall param st vd m caps. (HasCallStack, MonadCleveland caps m) => Alias -> st -> Contract param st vd -> m (ContractHandle param st vd)
- Test.Cleveland: originateLargeUntyped :: (HasCallStack, MonadCleveland caps m) => UntypedOriginateData -> m Address
- Test.Cleveland: originateLargeUntypedSimple :: (HasCallStack, MonadCleveland caps m) => Alias -> Value -> Contract -> m Address
- Test.Cleveland: originateSimple :: forall cp st vd m. (HasCallStack, MonadOps m) => Alias -> st -> Contract cp st vd -> m (ContractHandle cp st vd)
- Test.Cleveland: originateTypedSimple :: forall cp st vd m. (HasCallStack, MonadOps m, NiceParameter cp, NiceStorage st, NiceViewsDescriptor vd) => Alias -> st -> Contract (ToT cp) (ToT st) -> m (ContractHandle cp st vd)
- Test.Cleveland: originateUntyped :: (HasCallStack, MonadOps m) => UntypedOriginateData -> m Address
- Test.Cleveland: originateUntypedSimple :: (HasCallStack, MonadOps m) => Alias -> Value -> Contract -> m Address
- Test.Cleveland: transferMoney :: (HasCallStack, MonadOps m, ToAddress addr) => addr -> Mutez -> m ()
- Test.Cleveland.Instances: instance Data.String.IsString Morley.Tezos.Address.Alias.Alias
- Test.Cleveland.Internal.Abstract: [cmiEmulatedImpl] :: ClevelandMiscImpl m -> m (Maybe (EmulatedImpl m))
- Test.Cleveland.Internal.Abstract: [tfAddress] :: TransferFailure -> Address
- Test.Cleveland.Internal.Actions: call :: forall param vd addr m epRef epArg. (HasCallStack, MonadOps m, ToTAddress param vd addr, HasEntrypointArg param epRef epArg, IsoValue epArg, Typeable epArg) => addr -> epRef -> epArg -> m ()
- Test.Cleveland.Internal.Actions: instance (Test.Cleveland.Internal.Abstract.HasClevelandCaps caps, Test.Cleveland.Internal.Abstract.ClevelandBaseMonad caps GHC.Types.~ m) => Test.Cleveland.Internal.Actions.MonadOps (Control.Monad.Trans.Reader.ReaderT caps m)
- Test.Cleveland.Internal.Actions: instance Morley.Prelude.Boolean.Boolean Test.Cleveland.Internal.Actions.TransferFailurePredicate
- Test.Cleveland.Internal.Actions: instance Test.Cleveland.Internal.Actions.MonadOps Test.Cleveland.Internal.Abstract.ClevelandOpsBatch
- Test.Cleveland.Internal.Actions: originateLarge :: forall param st vd m caps. (HasCallStack, MonadCleveland caps m) => OriginateData param st vd -> m (ContractHandle param st vd)
- Test.Cleveland.Internal.Actions: originateLargeSimple :: forall param st vd m caps. (HasCallStack, MonadCleveland caps m) => Alias -> st -> Contract param st vd -> m (ContractHandle param st vd)
- Test.Cleveland.Internal.Actions: originateLargeUntyped :: (HasCallStack, MonadCleveland caps m) => UntypedOriginateData -> m Address
- Test.Cleveland.Internal.Actions: originateLargeUntypedSimple :: (HasCallStack, MonadCleveland caps m) => Alias -> Value -> Contract -> m Address
- Test.Cleveland.Internal.Actions: originateSimple :: forall cp st vd m. (HasCallStack, MonadOps m) => Alias -> st -> Contract cp st vd -> m (ContractHandle cp st vd)
- Test.Cleveland.Internal.Actions: originateTypedSimple :: forall cp st vd m. (HasCallStack, MonadOps m, NiceParameter cp, NiceStorage st, NiceViewsDescriptor vd) => Alias -> st -> Contract (ToT cp) (ToT st) -> m (ContractHandle cp st vd)
- Test.Cleveland.Internal.Actions: originateUntyped :: (HasCallStack, MonadOps m) => UntypedOriginateData -> m Address
- Test.Cleveland.Internal.Actions: originateUntypedSimple :: (HasCallStack, MonadOps m) => Alias -> Value -> Contract -> m Address
- Test.Cleveland.Internal.Actions: transferMoney :: (HasCallStack, MonadOps m, ToAddress addr) => addr -> Mutez -> m ()
- Test.Cleveland.Internal.Actions: withCap :: Monad m => (caps -> cap) -> (cap -> m a) -> ReaderT caps m a
- Test.Cleveland.Internal.Actions: withOpsCap :: MonadOps m => (ClevelandOpsImpl m -> m a) -> m a
- Test.Cleveland.Internal.Client: NetworkEnv :: MorleyClientEnv -> Maybe SecretKey -> Alias -> Bool -> NetworkEnv
- Test.Cleveland.Internal.Client: [neExplicitDataDir] :: NetworkEnv -> Bool
- Test.Cleveland.Internal.Client: [neMoneybagAlias] :: NetworkEnv -> Alias
- Test.Cleveland.Internal.Client: [neMorleyClientEnv] :: NetworkEnv -> MorleyClientEnv
- Test.Cleveland.Internal.Client: [neSecretKey] :: NetworkEnv -> Maybe SecretKey
- Test.Cleveland.Internal.Client: data NetworkEnv
- Test.Cleveland.Internal.Client: runClevelandT :: NetworkEnv -> ClevelandT ClientM a -> IO a
- Test.Cleveland.Internal.Pure: UnexpectedBigMapKeyType :: MismatchError T -> TestError
- Test.Cleveland.Internal.Pure: UnexpectedBigMapValueType :: MismatchError T -> TestError
- Test.Cleveland.Internal.Pure: instance Formatting.Buildable.Buildable Test.Cleveland.Internal.Pure.AddressName
- Test.Cleveland.Internal.Pure: instance GHC.Classes.Eq Test.Cleveland.Internal.Pure.AliasData
- Test.Cleveland.Internal.Pure: instance GHC.Show.Show Test.Cleveland.Internal.Pure.AddressName
- Test.Cleveland.Internal.Pure: instance GHC.Show.Show Test.Cleveland.Internal.Pure.AliasData
- Test.Cleveland.Internal.Pure: psAliases :: Lens' PureState Aliases
- Test.Cleveland.Internal.Pure: psContractsNames :: Lens' PureState (Map Address Text)
- Test.Cleveland.Internal.Pure: runClevelandT :: Alias -> ClevelandT PureM a -> IO a
- Test.Cleveland.Internal.Scenario: [ScenarioCleveland] :: ClevelandT m () -> Scenario m
- Test.Cleveland.Internal.Scenario: data Scenario m
- Test.Cleveland.Lorentz.Types: instance Lorentz.Constraints.Scopes.NiceStorage st => Test.Cleveland.Lorentz.Types.ToStorageType st Morley.Tezos.Address.Address
+ Test.Cleveland: ArgF :: f a -> NamedF (f :: Type -> Type) a (name :: Symbol)
+ Test.Cleveland: ContractEvent :: ContractAddress -> Text -> Maybe SomeAnnotatedValue -> ContractEvent
+ Test.Cleveland: Large :: Large
+ Test.Cleveland: WithContractEvents :: WithContractEvents
+ Test.Cleveland: [TypedContract] :: Contract (ToT cp) (ToT st) -> TypedContract cp st vd
+ Test.Cleveland: [cePayload] :: ContractEvent -> Maybe SomeAnnotatedValue
+ Test.Cleveland: [ceSource] :: ContractEvent -> ContractAddress
+ Test.Cleveland: [ceTag] :: ContractEvent -> Text
+ Test.Cleveland: calling :: forall mname. EntrypointRef mname -> forall epArg param. (NiceParameter epArg, HasEntrypointArg param (EntrypointRef mname) epArg) => epArg -> GenericCall ('Checked param)
+ Test.Cleveland: class Default a
+ Test.Cleveland: class MonadFail m => MonadScenario m
+ Test.Cleveland: class ToAddress a
+ Test.Cleveland: class ToL1Address addr
+ Test.Cleveland: class (ToTAddress cp vd addr, ToL1Address addr) => ToL1TAddress cp vd addr
+ Test.Cleveland: data ClientM a
+ Test.Cleveland: data ContractEvent
+ Test.Cleveland: data KindedAddress (kind :: AddressKind)
+ Test.Cleveland: data Large
+ Test.Cleveland: data Mutez
+ Test.Cleveland: data TypedContract cp st vd
+ Test.Cleveland: data WithContractEvents
+ Test.Cleveland: def :: Default a => a
+ Test.Cleveland: getMorleyClientEnv :: MonadNetwork caps m => m MorleyClientEnv
+ Test.Cleveland: newtype NamedF (f :: Type -> Type) a (name :: Symbol)
+ Test.Cleveland: pattern (:!) :: Name name -> a -> NamedF Identity a name
+ Test.Cleveland: pattern Arg :: a -> name :! a
+ Test.Cleveland: scenarioNetwork :: NetworkT ClientM () -> Scenario' ClientM
+ Test.Cleveland: toAddress :: ToAddress a => a -> Address
+ Test.Cleveland: toL1Address :: ToL1Address addr => addr -> L1Address
+ Test.Cleveland: toL1TAddress :: ToL1TAddress cp vd addr => addr -> L1TAddress cp vd
+ Test.Cleveland: type (name :: Symbol) :! a = NamedF Identity a name
+ Test.Cleveland: type ContractAddress = KindedAddress 'AddressKindContract
+ Test.Cleveland: type ContractAlias = Alias 'AddressKindContract
+ Test.Cleveland: type ImplicitAddress = KindedAddress 'AddressKindImplicit
+ Test.Cleveland: type ImplicitAlias = Alias 'AddressKindImplicit
+ Test.Cleveland: type Scenario m = MonadScenario m => Scenario' m
+ Test.Cleveland: tz :: QuasiQuoter
+ Test.Cleveland: unsafeCalling :: EpName -> forall epArg. NiceParameter epArg => epArg -> GenericCall 'Unchecked
+ Test.Cleveland.Instances: instance (mname GHC.Types.~ 'GHC.Maybe.Nothing) => Data.Default.Class.Default (Lorentz.Entrypoints.Core.EntrypointRef mname)
+ Test.Cleveland.Instances: instance Data.Default.Class.Default Morley.Michelson.Untyped.Entrypoints.EpName
+ Test.Cleveland.Instances: instance Data.String.IsString Morley.Tezos.Address.Alias.ContractAlias
+ Test.Cleveland.Instances: instance Data.String.IsString Morley.Tezos.Address.Alias.ImplicitAlias
+ Test.Cleveland.Instances: instance Lorentz.Entrypoints.Core.NiceEntrypointName sym => GHC.OverloadedLabels.IsLabel sym Morley.Michelson.Untyped.Entrypoints.EpName
+ Test.Cleveland.Internal.Abstract: AddressAndAlias :: Address -> Maybe ContractAlias -> AddressAndAlias
+ Test.Cleveland.Internal.Abstract: ContractEvent :: ContractAddress -> Text -> Maybe SomeAnnotatedValue -> ContractEvent
+ Test.Cleveland.Internal.Abstract: IsLarge :: LargeOrigination
+ Test.Cleveland.Internal.Abstract: NetworkCaps :: NetworkEnv -> ClevelandCaps m -> NetworkCaps m
+ Test.Cleveland.Internal.Abstract: NetworkEnv :: MorleyClientEnv -> Maybe SecretKey -> ImplicitAlias -> Bool -> NetworkEnv
+ Test.Cleveland.Internal.Abstract: NotLarge :: LargeOrigination
+ Test.Cleveland.Internal.Abstract: TypedOriginateData :: ContractAlias -> Mutez -> st -> Contract (ToT cp) (ToT st) -> TypedOriginateData cp st vd (large :: LargeOrigination)
+ Test.Cleveland.Internal.Abstract: [TypedContract] :: Contract (ToT cp) (ToT st) -> TypedContract cp st vd
+ Test.Cleveland.Internal.Abstract: [cePayload] :: ContractEvent -> Maybe SomeAnnotatedValue
+ Test.Cleveland.Internal.Abstract: [ceSource] :: ContractEvent -> ContractAddress
+ Test.Cleveland.Internal.Abstract: [ceTag] :: ContractEvent -> Text
+ Test.Cleveland.Internal.Abstract: [cmiUnderlyingImpl] :: ClevelandMiscImpl m -> m (Either (EmulatedImpl m) NetworkEnv)
+ Test.Cleveland.Internal.Abstract: [ncClevelandCaps] :: NetworkCaps m -> ClevelandCaps m
+ Test.Cleveland.Internal.Abstract: [ncNetworkEnv] :: NetworkCaps m -> NetworkEnv
+ Test.Cleveland.Internal.Abstract: [neExplicitDataDir] :: NetworkEnv -> Bool
+ Test.Cleveland.Internal.Abstract: [neMoneybagAlias] :: NetworkEnv -> ImplicitAlias
+ Test.Cleveland.Internal.Abstract: [neMorleyClientEnv] :: NetworkEnv -> MorleyClientEnv
+ Test.Cleveland.Internal.Abstract: [neSecretKey] :: NetworkEnv -> Maybe SecretKey
+ Test.Cleveland.Internal.Abstract: [tfAddressAndAlias] :: TransferFailure -> AddressAndAlias
+ Test.Cleveland.Internal.Abstract: [todBalance] :: TypedOriginateData cp st vd (large :: LargeOrigination) -> Mutez
+ Test.Cleveland.Internal.Abstract: [todContract] :: TypedOriginateData cp st vd (large :: LargeOrigination) -> Contract (ToT cp) (ToT st)
+ Test.Cleveland.Internal.Abstract: [todName] :: TypedOriginateData cp st vd (large :: LargeOrigination) -> ContractAlias
+ Test.Cleveland.Internal.Abstract: [todStorage] :: TypedOriginateData cp st vd (large :: LargeOrigination) -> st
+ Test.Cleveland.Internal.Abstract: class HasClevelandCaps caps => HasNetworkCaps caps
+ Test.Cleveland.Internal.Abstract: data AddressAndAlias
+ Test.Cleveland.Internal.Abstract: data ClevelandResult
+ Test.Cleveland.Internal.Abstract: data ContractEvent
+ Test.Cleveland.Internal.Abstract: data KindedAddress (kind :: AddressKind)
+ Test.Cleveland.Internal.Abstract: data LargeOrigination
+ Test.Cleveland.Internal.Abstract: data NetworkCaps m
+ Test.Cleveland.Internal.Abstract: data NetworkEnv
+ Test.Cleveland.Internal.Abstract: data TypedContract cp st vd
+ Test.Cleveland.Internal.Abstract: data TypedOriginateData cp st vd (large :: LargeOrigination)
+ Test.Cleveland.Internal.Abstract: getNetworkEnvCap :: HasNetworkCaps caps => caps -> NetworkEnv
+ Test.Cleveland.Internal.Abstract: instance (Lorentz.Entrypoints.Core.NiceEntrypointName epName, mname GHC.Types.~ 'GHC.Maybe.Just epName) => Test.Cleveland.Internal.Abstract.EntrypointNameConstructor epName (Lorentz.Entrypoints.Core.EntrypointRef mname)
+ Test.Cleveland.Internal.Abstract: instance (any GHC.Types.~ "", t GHC.Types.~ Data.Text.Internal.Text) => Test.Cleveland.Internal.Abstract.EntrypointNameConstructor any (t -> Morley.Michelson.Untyped.Entrypoints.EpName)
+ Test.Cleveland.Internal.Abstract: instance Formatting.Buildable.Buildable Test.Cleveland.Internal.Abstract.AddressAndAlias
+ Test.Cleveland.Internal.Abstract: instance GHC.Base.Monad m => Test.Cleveland.Internal.Abstract.HasClevelandCaps (Test.Cleveland.Internal.Abstract.NetworkCaps m)
+ Test.Cleveland.Internal.Abstract: instance GHC.Base.Monad m => Test.Cleveland.Internal.Abstract.HasNetworkCaps (Test.Cleveland.Internal.Abstract.NetworkCaps m)
+ Test.Cleveland.Internal.Abstract: instance GHC.Classes.Eq Test.Cleveland.Internal.Abstract.AddressAndAlias
+ Test.Cleveland.Internal.Abstract: instance GHC.Show.Show Test.Cleveland.Internal.Abstract.AddressAndAlias
+ Test.Cleveland.Internal.Abstract: instance Lorentz.Entrypoints.Core.NiceEntrypointName epName => Test.Cleveland.Internal.Abstract.EntrypointNameConstructor epName Morley.Michelson.Untyped.Entrypoints.EpName
+ Test.Cleveland.Internal.Abstract: instance Morley.Client.Types.OperationInfoDescriptor Test.Cleveland.Internal.Abstract.ClevelandResult
+ Test.Cleveland.Internal.Abstract: neExplicitDataDirL :: Lens' NetworkEnv Bool
+ Test.Cleveland.Internal.Abstract: neMoneybagAliasL :: Lens' NetworkEnv ImplicitAlias
+ Test.Cleveland.Internal.Abstract: neMorleyClientEnvL :: Lens' NetworkEnv MorleyClientEnv
+ Test.Cleveland.Internal.Abstract: neSecretKeyL :: Lens' NetworkEnv (Maybe SecretKey)
+ Test.Cleveland.Internal.Abstract: type ContractAddress = KindedAddress 'AddressKindContract
+ Test.Cleveland.Internal.Abstract: type ContractAlias = Alias 'AddressKindContract
+ Test.Cleveland.Internal.Abstract: type ImplicitAddress = KindedAddress 'AddressKindImplicit
+ Test.Cleveland.Internal.Abstract: type ImplicitAlias = Alias 'AddressKindImplicit
+ Test.Cleveland.Internal.Abstract: type MonadNetwork caps m = (MonadCleveland caps m, HasNetworkCaps caps)
+ Test.Cleveland.Internal.Abstract: type NetworkT m = ReaderT (NetworkCaps m) m
+ Test.Cleveland.Internal.Actions: Large :: Large
+ Test.Cleveland.Internal.Actions: WithContractEvents :: WithContractEvents
+ Test.Cleveland.Internal.Actions: calling :: forall mname. EntrypointRef mname -> forall epArg param. (NiceParameter epArg, HasEntrypointArg param (EntrypointRef mname) epArg) => epArg -> GenericCall ('Checked param)
+ Test.Cleveland.Internal.Actions: class (forall ct bal large a. OFConstraint ct large (m a) => OriginateFunc ct bal large (m a)) => MonadOriginate m
+ Test.Cleveland.Internal.Actions: class (forall mod am emit a. (SingI emit, DoTransfer mod, a ~ FTransferResult emit) => TransferFunc mod emit am (m a)) => MonadTransfer m
+ Test.Cleveland.Internal.Actions: data Large
+ Test.Cleveland.Internal.Actions: data WithContractEvents
+ Test.Cleveland.Internal.Actions: getMorleyClientEnv :: MonadNetwork caps m => m MorleyClientEnv
+ Test.Cleveland.Internal.Actions: instance (Test.Cleveland.Internal.Actions.Transfer.MonadTransfer m, Test.Cleveland.Internal.Actions.Originate.MonadOriginate m) => Test.Cleveland.Internal.Actions.MonadOps m
+ Test.Cleveland.Internal.Actions: unsafeCalling :: EpName -> forall epArg. NiceParameter epArg => epArg -> GenericCall 'Unchecked
+ Test.Cleveland.Internal.Actions.Assertions: (@/=) :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a) => a -> a -> m ()
+ Test.Cleveland.Internal.Actions.Assertions: (@==) :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a) => a -> a -> m ()
+ Test.Cleveland.Internal.Actions.Assertions: (@@/=) :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a) => m a -> a -> m ()
+ Test.Cleveland.Internal.Actions.Assertions: (@@==) :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a) => m a -> a -> m ()
+ Test.Cleveland.Internal.Actions.Assertions: assert :: (HasCallStack, MonadCleveland caps m) => Bool -> Builder -> m ()
+ Test.Cleveland.Internal.Actions.Assertions: checkCompares :: forall a b caps m. (HasCallStack, MonadCleveland caps m, Buildable a, Buildable b) => a -> (a -> b -> Bool) -> b -> m ()
+ Test.Cleveland.Internal.Actions.Assertions: checkComparesWith :: forall a b caps m. (HasCallStack, MonadCleveland caps m) => (a -> Text) -> a -> (a -> b -> Bool) -> (b -> Text) -> b -> m ()
+ Test.Cleveland.Internal.Actions.Assertions: evalJust :: (HasCallStack, MonadCleveland caps m) => Builder -> Maybe a -> m a
+ Test.Cleveland.Internal.Actions.Assertions: evalRight :: (HasCallStack, MonadCleveland caps m) => (a -> Builder) -> Either a b -> m b
+ Test.Cleveland.Internal.Actions.Assertions: failure :: forall a caps m. (HasCallStack, MonadCleveland caps m) => Builder -> m a
+ Test.Cleveland.Internal.Actions.Assertions: infix 1 @@/=
+ Test.Cleveland.Internal.Actions.ExceptionHandling: attempt :: forall e caps m a. (HasCallStack, MonadCleveland caps m, Exception e) => m a -> m (Either e a)
+ Test.Cleveland.Internal.Actions.ExceptionHandling: catchTransferFailure :: (HasCallStack, MonadCleveland caps m) => m a -> m TransferFailure
+ Test.Cleveland.Internal.Actions.ExceptionHandling: checkTransferFailure :: (HasCallStack, MonadCleveland caps m) => TransferFailure -> TransferFailurePredicate -> m ()
+ Test.Cleveland.Internal.Actions.ExceptionHandling: clarifyErrors :: forall caps m a. MonadCleveland caps m => Builder -> m a -> m a
+ Test.Cleveland.Internal.Actions.ExceptionHandling: expectCustomError :: forall arg a tag caps m. (HasCallStack, MonadCleveland caps m, IsError (CustomError tag), MustHaveErrorArg tag (MText, arg)) => Label tag -> arg -> m a -> m ()
+ Test.Cleveland.Internal.Actions.ExceptionHandling: expectCustomErrorNoArg :: (HasCallStack, MonadCleveland caps m, IsError (CustomError tag), MustHaveErrorArg tag MText) => Label tag -> m a -> m ()
+ Test.Cleveland.Internal.Actions.ExceptionHandling: expectCustomError_ :: (HasCallStack, MonadCleveland caps m, IsError (CustomError tag), MustHaveErrorArg tag (MText, ())) => Label tag -> m a -> m ()
+ Test.Cleveland.Internal.Actions.ExceptionHandling: expectError :: forall err a caps m. (HasCallStack, MonadCleveland caps m, IsError err) => err -> m a -> m ()
+ Test.Cleveland.Internal.Actions.ExceptionHandling: expectFailedWith :: forall err a caps m. (HasCallStack, MonadCleveland caps m, NiceConstant err) => err -> m a -> m ()
+ Test.Cleveland.Internal.Actions.ExceptionHandling: expectNumericError :: forall err a caps m. (HasCallStack, MonadCleveland caps m, IsError err) => ErrorTagMap -> err -> m a -> m ()
+ Test.Cleveland.Internal.Actions.ExceptionHandling: expectTransferFailure :: (HasCallStack, MonadCleveland caps m) => TransferFailurePredicate -> m a -> m ()
+ Test.Cleveland.Internal.Actions.Helpers: withCap :: Monad m => (caps -> cap) -> (cap -> m a) -> ReaderT caps m a
+ Test.Cleveland.Internal.Actions.Misc: advanceLevel :: forall caps m. (HasCallStack, MonadCleveland caps m) => Natural -> m ()
+ Test.Cleveland.Internal.Actions.Misc: advanceTime :: forall unit caps m. (HasCallStack, MonadCleveland caps m, KnownDivRat unit Second) => Time unit -> m ()
+ Test.Cleveland.Internal.Actions.Misc: advanceToLevel :: forall caps m. (HasCallStack, MonadCleveland caps m) => Natural -> m ()
+ Test.Cleveland.Internal.Actions.Misc: branchout :: forall caps m. MonadEmulated caps m => [(Text, m ())] -> m ()
+ Test.Cleveland.Internal.Actions.Misc: comment :: (HasCallStack, MonadCleveland caps m) => Text -> m ()
+ Test.Cleveland.Internal.Actions.Misc: enumAliases :: forall n n'. (SingIPeano n, IsoNatPeano n n') => ImplicitAlias -> SizedList n SpecificOrDefaultAlias
+ Test.Cleveland.Internal.Actions.Misc: getAllBigMapValues :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NiceUnpackedValue v) => BigMapId k v -> m [v]
+ Test.Cleveland.Internal.Actions.Misc: getAllBigMapValuesMaybe :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NiceUnpackedValue v) => BigMapId k v -> m (Maybe [v])
+ Test.Cleveland.Internal.Actions.Misc: getApproximateBlockInterval :: (HasCallStack, MonadCleveland caps m) => m (Time Second)
+ Test.Cleveland.Internal.Actions.Misc: getBalance :: (HasCallStack, MonadCleveland caps m, ToL1Address addr) => addr -> m Mutez
+ Test.Cleveland.Internal.Actions.Misc: getBigMapSize :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NiceUnpackedValue v) => BigMapId k v -> m Natural
+ Test.Cleveland.Internal.Actions.Misc: getBigMapSizeMaybe :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NiceUnpackedValue v) => BigMapId k v -> m (Maybe Natural)
+ Test.Cleveland.Internal.Actions.Misc: getBigMapValue :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NicePackedValue k, NiceUnpackedValue v, Buildable k) => BigMapId k v -> k -> m v
+ Test.Cleveland.Internal.Actions.Misc: getBigMapValueMaybe :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NicePackedValue k, NiceUnpackedValue v) => BigMapId k v -> k -> m (Maybe v)
+ Test.Cleveland.Internal.Actions.Misc: getChainId :: (HasCallStack, MonadCleveland caps m) => m ChainId
+ Test.Cleveland.Internal.Actions.Misc: getDelegate :: (HasCallStack, MonadCleveland caps m, ToContractAddress addr) => addr -> m (Maybe KeyHash)
+ Test.Cleveland.Internal.Actions.Misc: getFullStorage :: forall st addr caps m. (HasCallStack, MonadEmulated caps m, ToStorageType st addr) => addr -> m st
+ Test.Cleveland.Internal.Actions.Misc: getLevel :: (HasCallStack, MonadCleveland caps m) => m Natural
+ Test.Cleveland.Internal.Actions.Misc: getMinBlockTime :: (HasCallStack, MonadCleveland caps m) => m Natural
+ Test.Cleveland.Internal.Actions.Misc: getMorleyClientEnv :: MonadNetwork caps m => m MorleyClientEnv
+ Test.Cleveland.Internal.Actions.Misc: getMorleyLogs :: forall a caps m. MonadEmulated caps m => m a -> m (LogsInfo, a)
+ Test.Cleveland.Internal.Actions.Misc: getMorleyLogs_ :: MonadEmulated caps m => m () -> m LogsInfo
+ Test.Cleveland.Internal.Actions.Misc: getNow :: (HasCallStack, MonadCleveland caps m) => m Timestamp
+ Test.Cleveland.Internal.Actions.Misc: getPublicKey :: (HasCallStack, MonadCleveland caps m) => ImplicitAddress -> m PublicKey
+ Test.Cleveland.Internal.Actions.Misc: getSomeStorage :: forall addr caps m. (HasCallStack, MonadCleveland caps m, ToContractAddress addr) => addr -> m SomeAnnotatedValue
+ Test.Cleveland.Internal.Actions.Misc: getStorage :: forall st addr caps m. (HasCallStack, MonadCleveland caps m, ToStorageType st addr, IsoValue (AsRPC st)) => addr -> m (AsRPC st)
+ Test.Cleveland.Internal.Actions.Misc: ifEmulation :: forall a caps m. MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadEmulated caps1 m1) => m1 a) -> (forall caps1 m1. (EqBaseMonad caps caps1, MonadNetwork caps1 m1) => m1 a) -> m a
+ Test.Cleveland.Internal.Actions.Misc: importContract :: (HasCallStack, NiceParameter param, NiceStorage st, NiceViewsDescriptor vd, DemoteViewsDescriptor vd, MonadCleveland caps m) => FilePath -> m (Contract param st vd)
+ Test.Cleveland.Internal.Actions.Misc: importUntypedContract :: (HasCallStack, MonadCleveland caps m) => FilePath -> m Contract
+ Test.Cleveland.Internal.Actions.Misc: inBatch :: (HasCallStack, MonadCleveland caps m) => ClevelandOpsBatch a -> m a
+ Test.Cleveland.Internal.Actions.Misc: newAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m ImplicitAddress
+ Test.Cleveland.Internal.Actions.Misc: newAddresses :: forall n n' caps m. (HasCallStack, MonadCleveland caps m, IsoNatPeano n n') => SizedList n SpecificOrDefaultAlias -> m (SizedList n ImplicitAddress)
+ Test.Cleveland.Internal.Actions.Misc: newFreshAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m ImplicitAddress
+ Test.Cleveland.Internal.Actions.Misc: noViews :: forall {k1} {k2} contract (cp :: k1) (st :: k2). contract cp st () -> contract cp st ()
+ Test.Cleveland.Internal.Actions.Misc: offshoot :: forall caps m. MonadEmulated caps m => Text -> m () -> m ()
+ Test.Cleveland.Internal.Actions.Misc: refillable :: MonadCleveland caps m => m ImplicitAddress -> m ImplicitAddress
+ Test.Cleveland.Internal.Actions.Misc: registerDelegate :: (HasCallStack, MonadCleveland caps m) => ImplicitAddress -> m ()
+ Test.Cleveland.Internal.Actions.Misc: resolveAddress :: (HasCallStack, MonadCleveland caps m) => Alias kind -> m (KindedAddress kind)
+ Test.Cleveland.Internal.Actions.Misc: runCode :: (HasCallStack, MonadCleveland caps m, HasRPCRepr st, IsoValue (AsRPC st)) => RunCode cp st vd -> m (AsRPC st)
+ Test.Cleveland.Internal.Actions.Misc: runIO :: (HasCallStack, MonadCleveland caps m) => IO res -> m res
+ Test.Cleveland.Internal.Actions.Misc: setVotingPowers :: MonadEmulated caps m => VotingPowers -> m ()
+ Test.Cleveland.Internal.Actions.Misc: signBinary :: (HasCallStack, BytesLike bs, MonadCleveland caps m) => bs -> ImplicitAddress -> m (TSignature bs)
+ Test.Cleveland.Internal.Actions.Misc: signBytes :: (HasCallStack, MonadCleveland caps m) => ByteString -> ImplicitAddress -> m Signature
+ Test.Cleveland.Internal.Actions.Misc: type EqBaseMonad a b = ClevelandBaseMonad a ~ ClevelandBaseMonad b
+ Test.Cleveland.Internal.Actions.Misc: whenEmulation :: MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadEmulated caps1 m1) => m1 ()) -> m ()
+ Test.Cleveland.Internal.Actions.Misc: whenNetwork :: MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadNetwork caps1 m1) => m1 ()) -> m ()
+ Test.Cleveland.Internal.Actions.Misc: withMoneybag :: MonadCleveland caps m => ImplicitAddress -> m a -> m a
+ Test.Cleveland.Internal.Actions.Misc: withSender :: MonadCleveland caps m => ImplicitAddress -> m a -> m a
+ Test.Cleveland.Internal.Actions.MonadOps: class Functor m => MonadOpsInternal m
+ Test.Cleveland.Internal.Actions.MonadOps: instance (Test.Cleveland.Internal.Abstract.HasClevelandCaps caps, Test.Cleveland.Internal.Abstract.ClevelandBaseMonad caps GHC.Types.~ m) => Test.Cleveland.Internal.Actions.MonadOps.MonadOpsInternal (Control.Monad.Trans.Reader.ReaderT caps m)
+ Test.Cleveland.Internal.Actions.MonadOps: instance Test.Cleveland.Internal.Actions.MonadOps.MonadOpsInternal Test.Cleveland.Internal.Abstract.ClevelandOpsBatch
+ Test.Cleveland.Internal.Actions.MonadOps: withOpsCap :: MonadOpsInternal m => (ClevelandOpsImpl m -> m a) -> m a
+ Test.Cleveland.Internal.Actions.Originate: HasBalance :: HasBalance
+ Test.Cleveland.Internal.Actions.Originate: Large :: Large
+ Test.Cleveland.Internal.Actions.Originate: NoBalance :: HasBalance
+ Test.Cleveland.Internal.Actions.Originate: class ContractClass contract where {
+ Test.Cleveland.Internal.Actions.Originate: class ModifyOriginationData od
+ Test.Cleveland.Internal.Actions.Originate: class (forall ct bal large a. OFConstraint ct large (m a) => OriginateFunc ct bal large (m a)) => MonadOriginate m
+ Test.Cleveland.Internal.Actions.Originate: class ContractClass contract => OriginateFunc contract (bal :: HasBalance) isLarge r
+ Test.Cleveland.Internal.Actions.Originate: class Originator od res
+ Test.Cleveland.Internal.Actions.Originate: data HasBalance
+ Test.Cleveland.Internal.Actions.Originate: data Large
+ Test.Cleveland.Internal.Actions.Originate: initialData :: ContractClass contract => ContractAlias -> ContractStorage contract -> contract -> ContractOriginateData contract 'NotLarge
+ Test.Cleveland.Internal.Actions.Originate: instance (Test.Cleveland.Internal.Abstract.HasClevelandCaps caps, base GHC.Types.~ Test.Cleveland.Internal.Abstract.ClevelandBaseMonad caps, a GHC.Types.~ Morley.Tezos.Address.ContractAddress) => Test.Cleveland.Internal.Actions.Originate.Originator (Test.Cleveland.Internal.Abstract.UntypedOriginateData 'Test.Cleveland.Internal.Abstract.IsLarge) (Control.Monad.Trans.Reader.ReaderT caps base a)
+ Test.Cleveland.Internal.Actions.Originate: instance (Test.Cleveland.Internal.Actions.Originate.ContractClass ct, (TypeError ...)) => Test.Cleveland.Internal.Actions.Originate.OriginateFunc ct bal large (x -> r)
+ Test.Cleveland.Internal.Actions.Originate: instance (Test.Cleveland.Internal.Actions.Originate.ModifyOriginationData (Test.Cleveland.Internal.Actions.Originate.ContractOriginateData ct), Test.Cleveland.Internal.Actions.Originate.OriginateFunc ct 'Test.Cleveland.Internal.Actions.Originate.HasBalance isLarge r, Test.Cleveland.Internal.Actions.Originate.CheckDupBalance bal, bal GHC.Types.~ 'Test.Cleveland.Internal.Actions.Originate.NoBalance) => Test.Cleveland.Internal.Actions.Originate.OriginateFunc ct bal isLarge (Morley.Tezos.Core.Mutez -> r)
+ Test.Cleveland.Internal.Actions.Originate: instance (Test.Cleveland.Internal.Actions.Originate.ModifyOriginationData (Test.Cleveland.Internal.Actions.Originate.ContractOriginateData ct), Test.Cleveland.Internal.Actions.Originate.OriginateFunc ct bal 'Test.Cleveland.Internal.Abstract.IsLarge r, Test.Cleveland.Internal.Actions.Originate.CheckDupLarge isLarge, isLarge GHC.Types.~ 'Test.Cleveland.Internal.Abstract.NotLarge) => Test.Cleveland.Internal.Actions.Originate.OriginateFunc ct bal isLarge (Test.Cleveland.Internal.Actions.Originate.Large -> r)
+ Test.Cleveland.Internal.Actions.Originate: instance (a GHC.Types.~ Morley.Tezos.Address.ContractAddress, Test.Cleveland.Internal.Actions.MonadOps.MonadOpsInternal m) => Test.Cleveland.Internal.Actions.Originate.Originator (Test.Cleveland.Internal.Abstract.UntypedOriginateData 'Test.Cleveland.Internal.Abstract.NotLarge) (m a)
+ Test.Cleveland.Internal.Actions.Originate: instance (a GHC.Types.~ Test.Cleveland.Lorentz.Types.ContractHandle cp st vd, Test.Cleveland.Internal.Actions.MonadOps.MonadOpsInternal m, Test.Cleveland.Internal.Actions.Originate.Originator (Test.Cleveland.Internal.Abstract.UntypedOriginateData large) (m Morley.Tezos.Address.ContractAddress)) => Test.Cleveland.Internal.Actions.Originate.Originator (Test.Cleveland.Internal.Abstract.OriginateData cp st vd large) (m a)
+ Test.Cleveland.Internal.Actions.Originate: instance (a GHC.Types.~ Test.Cleveland.Lorentz.Types.ContractHandle cp st vd, Test.Cleveland.Internal.Actions.MonadOps.MonadOpsInternal m, Test.Cleveland.Internal.Actions.Originate.Originator (Test.Cleveland.Internal.Abstract.UntypedOriginateData large) (m Morley.Tezos.Address.ContractAddress), Lorentz.Constraints.Scopes.NiceStorage st, Lorentz.Constraints.Derivative.NiceViewsDescriptor vd, Lorentz.Constraints.Scopes.NiceParameter cp) => Test.Cleveland.Internal.Actions.Originate.Originator (Test.Cleveland.Internal.Abstract.TypedOriginateData cp st vd large) (m a)
+ Test.Cleveland.Internal.Actions.Originate: instance Test.Cleveland.Internal.Actions.Originate.ContractClass (Lorentz.Base.Contract cp st vd)
+ Test.Cleveland.Internal.Actions.Originate: instance Test.Cleveland.Internal.Actions.Originate.ContractClass Morley.Michelson.Untyped.Aliases.Contract
+ Test.Cleveland.Internal.Actions.Originate: instance Test.Cleveland.Internal.Actions.Originate.ModifyOriginationData (Test.Cleveland.Internal.Abstract.OriginateData cp st vd)
+ Test.Cleveland.Internal.Actions.Originate: instance Test.Cleveland.Internal.Actions.Originate.ModifyOriginationData Test.Cleveland.Internal.Abstract.UntypedOriginateData
+ Test.Cleveland.Internal.Actions.Originate: instance Test.Cleveland.Internal.Actions.Originate.OFConstraint ct large (Control.Monad.Trans.Reader.ReaderT cap base a) => Test.Cleveland.Internal.Actions.Originate.OriginateFunc ct bal large (Control.Monad.Trans.Reader.ReaderT cap base a)
+ Test.Cleveland.Internal.Actions.Originate: instance Test.Cleveland.Internal.Actions.Originate.OFConstraint ct large (Test.Cleveland.Internal.Abstract.ClevelandOpsBatch a) => Test.Cleveland.Internal.Actions.Originate.OriginateFunc ct bal large (Test.Cleveland.Internal.Abstract.ClevelandOpsBatch a)
+ Test.Cleveland.Internal.Actions.Originate: instance forall k (m :: k -> *). (forall ct (bal :: Test.Cleveland.Internal.Actions.Originate.HasBalance) (large :: Test.Cleveland.Internal.Abstract.LargeOrigination) (a :: k). Test.Cleveland.Internal.Actions.Originate.OFConstraint ct large (m a) => Test.Cleveland.Internal.Actions.Originate.OriginateFunc ct bal large (m a)) => Test.Cleveland.Internal.Actions.Originate.MonadOriginate m
+ Test.Cleveland.Internal.Actions.Originate: instance forall k cp st (vd :: k). Test.Cleveland.Internal.Actions.Originate.ContractClass (Test.Cleveland.Internal.Abstract.TypedContract cp st vd)
+ Test.Cleveland.Internal.Actions.Originate: instance forall k cp st (vd :: k). Test.Cleveland.Internal.Actions.Originate.ModifyOriginationData (Test.Cleveland.Internal.Abstract.TypedOriginateData cp st vd)
+ Test.Cleveland.Internal.Actions.Originate: originate :: forall contract r. (HasCallStack, OriginateFunc contract 'NoBalance 'NotLarge r) => ContractAlias -> ContractStorage contract -> contract -> r
+ Test.Cleveland.Internal.Actions.Originate: originate'r :: (OriginateFunc contract bal isLarge r, HasCallStack, Originator (ContractOriginateData contract isLarge) r) => ContractOriginateData contract isLarge -> r
+ Test.Cleveland.Internal.Actions.Originate: originateFn :: (Originator od res, HasCallStack) => od -> res
+ Test.Cleveland.Internal.Actions.Originate: setBalance :: ModifyOriginationData od => Mutez -> od large -> od large
+ Test.Cleveland.Internal.Actions.Originate: setLarge :: ModifyOriginationData od => od 'NotLarge -> od 'IsLarge
+ Test.Cleveland.Internal.Actions.Originate: type OFConstraint ct large r = (ContractClass ct, Originator (ContractOriginateData ct large) r)
+ Test.Cleveland.Internal.Actions.Originate: type family ContractOriginateData contract :: LargeOrigination -> Type;
+ Test.Cleveland.Internal.Actions.Originate: }
+ Test.Cleveland.Internal.Actions.Transfer: Checked :: Type -> TransferMode
+ Test.Cleveland.Internal.Actions.Transfer: GenericTransferData :: L1Address -> GenericCall mode -> Mutez -> GenericTransferData mode
+ Test.Cleveland.Internal.Actions.Transfer: HasAmount :: HasAmount
+ Test.Cleveland.Internal.Actions.Transfer: HasNoAmount :: HasAmount
+ Test.Cleveland.Internal.Actions.Transfer: Incomplete :: TransferMode -> TransferMode
+ Test.Cleveland.Internal.Actions.Transfer: TransferIgnoreResult :: TransferResult
+ Test.Cleveland.Internal.Actions.Transfer: TransferWithEmits :: TransferResult
+ Test.Cleveland.Internal.Actions.Transfer: Unchecked :: TransferMode
+ Test.Cleveland.Internal.Actions.Transfer: WithContractEvents :: WithContractEvents
+ Test.Cleveland.Internal.Actions.Transfer: [CheckedCall] :: (NiceParameter epArg, HasEntrypointArg param epRef epArg) => epRef -> epArg -> GenericCall ('Checked param)
+ Test.Cleveland.Internal.Actions.Transfer: [STransferIgnoreResult] :: STransferResult ('TransferIgnoreResult :: TransferResult)
+ Test.Cleveland.Internal.Actions.Transfer: [STransferWithEmits] :: STransferResult ('TransferWithEmits :: TransferResult)
+ Test.Cleveland.Internal.Actions.Transfer: [UncheckedCall] :: NiceParameter epArg => EpName -> epArg -> GenericCall 'Unchecked
+ Test.Cleveland.Internal.Actions.Transfer: [UnspecifiedCall] :: GenericCall ('Incomplete param)
+ Test.Cleveland.Internal.Actions.Transfer: [gtdAddr] :: GenericTransferData mode -> L1Address
+ Test.Cleveland.Internal.Actions.Transfer: [gtdAmount] :: GenericTransferData mode -> Mutez
+ Test.Cleveland.Internal.Actions.Transfer: [gtdCall] :: GenericTransferData mode -> GenericCall mode
+ Test.Cleveland.Internal.Actions.Transfer: calling :: forall mname. EntrypointRef mname -> forall epArg param. (NiceParameter epArg, HasEntrypointArg param (EntrypointRef mname) epArg) => epArg -> GenericCall ('Checked param)
+ Test.Cleveland.Internal.Actions.Transfer: class DoTransfer mode
+ Test.Cleveland.Internal.Actions.Transfer: class (forall mod am emit a. (SingI emit, DoTransfer mod, a ~ FTransferResult emit) => TransferFunc mod emit am (m a)) => MonadTransfer m
+ Test.Cleveland.Internal.Actions.Transfer: class TransferFunc (mode :: TransferMode) (emit :: TransferResult) (hasAmount :: HasAmount) r
+ Test.Cleveland.Internal.Actions.Transfer: data GenericCall mode
+ Test.Cleveland.Internal.Actions.Transfer: data GenericTransferData mode
+ Test.Cleveland.Internal.Actions.Transfer: data HasAmount
+ Test.Cleveland.Internal.Actions.Transfer: data STransferResult :: TransferResult -> Type
+ Test.Cleveland.Internal.Actions.Transfer: data TransferMode
+ Test.Cleveland.Internal.Actions.Transfer: data TransferResult
+ Test.Cleveland.Internal.Actions.Transfer: data WithContractEvents
+ Test.Cleveland.Internal.Actions.Transfer: doTransfer :: (DoTransfer mode, HasCallStack, MonadOpsInternal m) => GenericTransferData mode -> m [ContractEvent]
+ Test.Cleveland.Internal.Actions.Transfer: initialData :: ToL1Address addr => addr -> GenericTransferData ('Incomplete (InitialTransferMode addr))
+ Test.Cleveland.Internal.Actions.Transfer: instance (Data.Singletons.SingI emit, Test.Cleveland.Internal.Actions.Transfer.DoTransfer mode, Test.Cleveland.Internal.Abstract.HasClevelandCaps cap, base GHC.Types.~ Test.Cleveland.Internal.Abstract.ClevelandBaseMonad cap, a GHC.Types.~ Test.Cleveland.Internal.Actions.Transfer.FTransferResult emit) => Test.Cleveland.Internal.Actions.Transfer.TransferFunc mode emit am (Control.Monad.Trans.Reader.ReaderT cap base a)
+ Test.Cleveland.Internal.Actions.Transfer: instance (Data.Singletons.SingI emit, Test.Cleveland.Internal.Actions.Transfer.DoTransfer mode, a GHC.Types.~ Test.Cleveland.Internal.Actions.Transfer.FTransferResult emit) => Test.Cleveland.Internal.Actions.Transfer.TransferFunc mode emit am (Test.Cleveland.Internal.Abstract.ClevelandOpsBatch a)
+ Test.Cleveland.Internal.Actions.Transfer: instance (Test.Cleveland.Internal.Actions.Transfer.TransferFunc mode 'Test.Cleveland.Internal.Actions.Transfer.TransferWithEmits am r, Test.Cleveland.Internal.Actions.Transfer.NoDuplicateEmit emit, emit GHC.Types.~ 'Test.Cleveland.Internal.Actions.Transfer.TransferIgnoreResult) => Test.Cleveland.Internal.Actions.Transfer.TransferFunc mode emit am (Test.Cleveland.Internal.Actions.Transfer.WithContractEvents -> r)
+ Test.Cleveland.Internal.Actions.Transfer: instance (Test.Cleveland.Internal.Actions.Transfer.TransferFunc mode emit 'Test.Cleveland.Internal.Actions.Transfer.HasAmount r, Test.Cleveland.Internal.Actions.Transfer.NoDuplicateAmount am, am GHC.Types.~ 'Test.Cleveland.Internal.Actions.Transfer.HasNoAmount) => Test.Cleveland.Internal.Actions.Transfer.TransferFunc mode emit am (Morley.Tezos.Core.Mutez -> r)
+ Test.Cleveland.Internal.Actions.Transfer: instance (Test.Cleveland.Internal.Actions.Transfer.TransferFunc modeTo emit am r, Test.Cleveland.Internal.Actions.Transfer.MatchModes modeFrom modeTo) => Test.Cleveland.Internal.Actions.Transfer.TransferFunc modeFrom emit am (Test.Cleveland.Internal.Actions.Transfer.GenericCall modeTo -> r)
+ Test.Cleveland.Internal.Actions.Transfer: instance (TypeError ...) => Test.Cleveland.Internal.Actions.Transfer.TransferFunc mode emit am (x -> r)
+ Test.Cleveland.Internal.Actions.Transfer: instance (forall (mod :: Test.Cleveland.Internal.Actions.Transfer.TransferMode) (am :: Test.Cleveland.Internal.Actions.Transfer.HasAmount) (emit :: Test.Cleveland.Internal.Actions.Transfer.TransferResult) a. (Data.Singletons.SingI emit, Test.Cleveland.Internal.Actions.Transfer.DoTransfer mod, a GHC.Types.~ Test.Cleveland.Internal.Actions.Transfer.FTransferResult emit) => Test.Cleveland.Internal.Actions.Transfer.TransferFunc mod emit am (m a)) => Test.Cleveland.Internal.Actions.Transfer.MonadTransfer m
+ Test.Cleveland.Internal.Actions.Transfer: instance Data.Singletons.SingI 'Test.Cleveland.Internal.Actions.Transfer.TransferIgnoreResult
+ Test.Cleveland.Internal.Actions.Transfer: instance Data.Singletons.SingI 'Test.Cleveland.Internal.Actions.Transfer.TransferWithEmits
+ Test.Cleveland.Internal.Actions.Transfer: instance Data.Singletons.SingKind Test.Cleveland.Internal.Actions.Transfer.TransferResult
+ Test.Cleveland.Internal.Actions.Transfer: instance Lorentz.Entrypoints.Core.HasEntrypointArg param (Lorentz.Entrypoints.Core.EntrypointRef 'GHC.Maybe.Nothing) () => Test.Cleveland.Internal.Actions.Transfer.DoTransfer ('Test.Cleveland.Internal.Actions.Transfer.Incomplete ('Test.Cleveland.Internal.Actions.Transfer.Checked param))
+ Test.Cleveland.Internal.Actions.Transfer: instance Test.Cleveland.Internal.Actions.Transfer.DoTransfer 'Test.Cleveland.Internal.Actions.Transfer.Unchecked
+ Test.Cleveland.Internal.Actions.Transfer: instance Test.Cleveland.Internal.Actions.Transfer.DoTransfer ('Test.Cleveland.Internal.Actions.Transfer.Checked param)
+ Test.Cleveland.Internal.Actions.Transfer: instance Test.Cleveland.Internal.Actions.Transfer.DoTransfer ('Test.Cleveland.Internal.Actions.Transfer.Incomplete 'Test.Cleveland.Internal.Actions.Transfer.Unchecked)
+ Test.Cleveland.Internal.Actions.Transfer: runTransfer :: (HasCallStack, MonadOpsInternal m) => TransferData -> m [ContractEvent]
+ Test.Cleveland.Internal.Actions.Transfer: transfer :: forall addr r. (HasCallStack, TransferFunc ('Incomplete (InitialTransferMode addr)) 'TransferIgnoreResult 'HasNoAmount r, ToL1Address addr) => addr -> r
+ Test.Cleveland.Internal.Actions.Transfer: transfer'r :: (TransferFunc mode emit hasAmount r, HasCallStack) => GenericTransferData mode -> r
+ Test.Cleveland.Internal.Actions.Transfer: type family TransferIgnoreResultSym0 :: TransferResult
+ Test.Cleveland.Internal.Actions.Transfer: unsafeCalling :: EpName -> forall epArg. NiceParameter epArg => epArg -> GenericCall 'Unchecked
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: AndPredicate :: NonEmpty TransferFailurePredicate -> TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: OrPredicate :: NonEmpty TransferFailurePredicate -> TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: TransferFailurePredicate :: (TransferFailure -> Validation Builder ()) -> TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: addressIs :: ToAddress addr => addr -> TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: badParameter :: TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: constant :: forall err. NiceConstant err => err -> SomeConstant
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: customError :: forall arg tag. (IsError (CustomError tag), MustHaveErrorArg tag (MText, arg)) => Label tag -> arg -> SomeConstant
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: customErrorNoArg :: (IsError (CustomError tag), MustHaveErrorArg tag MText) => Label tag -> SomeConstant
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: customError_ :: (IsError (CustomError tag), MustHaveErrorArg tag (MText, ())) => Label tag -> SomeConstant
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: data TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: emptyTransaction :: TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: failedWith :: SomeConstant -> TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: gasExhaustion :: TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: instance Morley.Prelude.Boolean.Boolean Test.Cleveland.Internal.Actions.TransferFailurePredicate.TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: lerror :: forall err. IsError err => err -> SomeConstant
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: numericError :: forall err. IsError err => ErrorTagMap -> err -> SomeConstant
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: shiftOverflow :: TransferFailurePredicate
+ Test.Cleveland.Internal.Actions.TransferFailurePredicate: transferFailureReasonPredicate :: (TransferFailureReason -> Validation Builder ()) -> TransferFailurePredicate
+ Test.Cleveland.Internal.Client: runNetworkT :: NetworkEnv -> NetworkT ClientM a -> IO a
+ Test.Cleveland.Internal.Pure: UnexpectedBigMapType :: Natural -> MismatchError T -> TestError
+ Test.Cleveland.Internal.Pure: psSecretKeys :: Lens' PureState (Map ImplicitAddress SecretKey)
+ Test.Cleveland.Internal.Scenario: [ScenarioNetwork] :: NetworkT ClientM () -> Scenario' ClientM
+ Test.Cleveland.Internal.Scenario: class MonadFail m => MonadScenario m
+ Test.Cleveland.Internal.Scenario: data Scenario' m
+ Test.Cleveland.Internal.Scenario: instance Test.Cleveland.Internal.Scenario.MonadScenario Test.Cleveland.Internal.Client.ClientM
+ Test.Cleveland.Internal.Scenario: instance Test.Cleveland.Internal.Scenario.MonadScenario Test.Cleveland.Internal.Pure.PureM
+ Test.Cleveland.Internal.Scenario: scenarioNetwork :: NetworkT ClientM () -> Scenario' ClientM
+ Test.Cleveland.Internal.Scenario: type Scenario m = MonadScenario m => Scenario' m
+ Test.Cleveland.Lorentz: class ToContractAddress addr
+ Test.Cleveland.Lorentz: class ToL1Address addr
+ Test.Cleveland.Lorentz: class (ToTAddress cp vd addr, ToL1Address addr) => ToL1TAddress cp vd addr
+ Test.Cleveland.Lorentz: toContractAddress :: ToContractAddress addr => addr -> ContractAddress
+ Test.Cleveland.Lorentz: toL1Address :: ToL1Address addr => addr -> L1Address
+ Test.Cleveland.Lorentz: toL1TAddress :: ToL1TAddress cp vd addr => addr -> L1TAddress cp vd
+ Test.Cleveland.Lorentz.Types: L1TAddress :: L1Address -> L1TAddress cp vd
+ Test.Cleveland.Lorentz.Types: [unL1TAddress] :: L1TAddress cp vd -> L1Address
+ Test.Cleveland.Lorentz.Types: class ToContractAddress addr
+ Test.Cleveland.Lorentz.Types: class ToL1Address addr
+ Test.Cleveland.Lorentz.Types: class (ToTAddress cp vd addr, ToL1Address addr) => ToL1TAddress cp vd addr
+ Test.Cleveland.Lorentz.Types: instance (Lorentz.Address.ToTAddress cp vd addr, Test.Cleveland.Lorentz.Types.ToL1Address addr) => Test.Cleveland.Lorentz.Types.ToL1TAddress cp vd addr
+ Test.Cleveland.Lorentz.Types: instance (cp GHC.Types.~ cp', vd GHC.Types.~ vd') => Lorentz.Address.ToTAddress cp' vd' (Test.Cleveland.Lorentz.Types.L1TAddress cp vd)
+ Test.Cleveland.Lorentz.Types: instance Lorentz.Constraints.Scopes.NiceStorage st => Test.Cleveland.Lorentz.Types.ToStorageType st Morley.Tezos.Address.ContractAddress
+ Test.Cleveland.Lorentz.Types: instance Morley.Tezos.Address.L1AddressKind kind => Test.Cleveland.Lorentz.Types.ToL1Address (Morley.Tezos.Address.KindedAddress kind)
+ Test.Cleveland.Lorentz.Types: instance Test.Cleveland.Lorentz.Types.ToContractAddress (Test.Cleveland.Lorentz.Types.ContractHandle cp st vd)
+ Test.Cleveland.Lorentz.Types: instance Test.Cleveland.Lorentz.Types.ToContractAddress Morley.Tezos.Address.ContractAddress
+ Test.Cleveland.Lorentz.Types: instance Test.Cleveland.Lorentz.Types.ToL1Address (Test.Cleveland.Lorentz.Types.ContractHandle cp st vd)
+ Test.Cleveland.Lorentz.Types: instance Test.Cleveland.Lorentz.Types.ToL1Address Morley.Tezos.Address.L1Address
+ Test.Cleveland.Lorentz.Types: instance forall k1 k2 (cp :: k1) (vd :: k2). Test.Cleveland.Lorentz.Types.ToL1Address (Test.Cleveland.Lorentz.Types.L1TAddress cp vd)
+ Test.Cleveland.Lorentz.Types: newtype L1TAddress cp vd
+ Test.Cleveland.Lorentz.Types: toContractAddress :: ToContractAddress addr => addr -> ContractAddress
+ Test.Cleveland.Lorentz.Types: toL1Address :: ToL1Address addr => addr -> L1Address
+ Test.Cleveland.Lorentz.Types: toL1TAddress :: ToL1TAddress cp vd addr => addr -> L1TAddress cp vd
- Hedgehog.Gen.Tezos.Address: genContractAddress :: MonadGen m => m Address
+ Hedgehog.Gen.Tezos.Address: genContractAddress :: MonadGen m => m ContractAddress
- Hedgehog.Gen.Tezos.Address: genKeyAddress :: MonadGen m => m Address
+ Hedgehog.Gen.Tezos.Address: genKeyAddress :: MonadGen m => m ImplicitAddress
- Test.Cleveland: ContractHandle :: Text -> Address -> ContractHandle (cp :: Type) (st :: Type) (vd :: Type)
+ Test.Cleveland: ContractHandle :: ContractAlias -> ContractAddress -> ContractHandle (cp :: Type) (st :: Type) (vd :: Type)
- Test.Cleveland: NetworkEnv :: MorleyClientEnv -> Maybe SecretKey -> Alias -> Bool -> NetworkEnv
+ Test.Cleveland: NetworkEnv :: MorleyClientEnv -> Maybe SecretKey -> ImplicitAlias -> Bool -> NetworkEnv
- Test.Cleveland: RunCode :: Contract cp st vd -> MaybeRPC st -> MaybeRPC cp -> Mutez -> Maybe Natural -> Maybe Timestamp -> Mutez -> Maybe Address -> RunCode cp st vd
+ Test.Cleveland: RunCode :: Contract cp st vd -> Value -> Value -> Mutez -> Maybe Natural -> Maybe Timestamp -> Mutez -> Maybe ImplicitAddress -> RunCode cp st vd
- Test.Cleveland: [chAddress] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> Address
+ Test.Cleveland: [chAddress] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> ContractAddress
- Test.Cleveland: [chContractName] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> Text
+ Test.Cleveland: [chContractName] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> ContractAlias
- Test.Cleveland: [neMoneybagAlias] :: NetworkEnv -> Alias
+ Test.Cleveland: [neMoneybagAlias] :: NetworkEnv -> ImplicitAlias
- Test.Cleveland: [rcParameter] :: RunCode cp st vd -> MaybeRPC cp
+ Test.Cleveland: [rcParameter] :: RunCode cp st vd -> Value
- Test.Cleveland: [rcSource] :: RunCode cp st vd -> Maybe Address
+ Test.Cleveland: [rcSource] :: RunCode cp st vd -> Maybe ImplicitAddress
- Test.Cleveland: [rcStorage] :: RunCode cp st vd -> MaybeRPC st
+ Test.Cleveland: [rcStorage] :: RunCode cp st vd -> Value
- Test.Cleveland: class Functor m => MonadOps m
+ Test.Cleveland: class (MonadTransfer m, MonadOriginate m) => MonadOps m
- Test.Cleveland: data Alias
+ Test.Cleveland: data Alias (kind :: AddressKind)
- Test.Cleveland: enumAliases :: forall n n'. (SingIPeano n, IsoNatPeano n n') => Alias -> SizedList n SpecificOrDefaultAlias
+ Test.Cleveland: enumAliases :: forall n n'. (SingIPeano n, IsoNatPeano n n') => ImplicitAlias -> SizedList n SpecificOrDefaultAlias
- Test.Cleveland: ep :: HasCallStack => Text -> EpName
+ Test.Cleveland: ep :: EntrypointNameConstructor epName a => a
- Test.Cleveland: getBalance :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m Mutez
+ Test.Cleveland: getBalance :: (HasCallStack, MonadCleveland caps m, ToL1Address addr) => addr -> m Mutez
- Test.Cleveland: getDelegate :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m (Maybe KeyHash)
+ Test.Cleveland: getDelegate :: (HasCallStack, MonadCleveland caps m, ToContractAddress addr) => addr -> m (Maybe KeyHash)
- Test.Cleveland: getPublicKey :: (HasCallStack, MonadCleveland caps m) => Address -> m PublicKey
+ Test.Cleveland: getPublicKey :: (HasCallStack, MonadCleveland caps m) => ImplicitAddress -> m PublicKey
- Test.Cleveland: getSomeStorage :: forall addr caps m. (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m SomeAnnotatedValue
+ Test.Cleveland: getSomeStorage :: forall addr caps m. (HasCallStack, MonadCleveland caps m, ToContractAddress addr) => addr -> m SomeAnnotatedValue
- Test.Cleveland: ifEmulation :: forall a caps m. MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadEmulated caps1 m1) => m1 a) -> (forall caps1 m1. (EqBaseMonad caps caps1, MonadCleveland caps1 m1) => m1 a) -> m a
+ Test.Cleveland: ifEmulation :: forall a caps m. MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadEmulated caps1 m1) => m1 a) -> (forall caps1 m1. (EqBaseMonad caps caps1, MonadNetwork caps1 m1) => m1 a) -> m a
- Test.Cleveland: newAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m Address
+ Test.Cleveland: newAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m ImplicitAddress
- Test.Cleveland: newAddresses :: forall n n' caps m. (HasCallStack, MonadCleveland caps m, IsoNatPeano n n') => SizedList n SpecificOrDefaultAlias -> m (SizedList n Address)
+ Test.Cleveland: newAddresses :: forall n n' caps m. (HasCallStack, MonadCleveland caps m, IsoNatPeano n n') => SizedList n SpecificOrDefaultAlias -> m (SizedList n ImplicitAddress)
- Test.Cleveland: newFreshAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m Address
+ Test.Cleveland: newFreshAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m ImplicitAddress
- Test.Cleveland: originate :: forall cp st vd m. (HasCallStack, MonadOps m) => OriginateData cp st vd -> m (ContractHandle cp st vd)
+ Test.Cleveland: originate :: forall contract r. (HasCallStack, OriginateFunc contract 'NoBalance 'NotLarge r) => ContractAlias -> ContractStorage contract -> contract -> r
- Test.Cleveland: refillable :: MonadCleveland caps m => m Address -> m Address
+ Test.Cleveland: refillable :: MonadCleveland caps m => m ImplicitAddress -> m ImplicitAddress
- Test.Cleveland: registerDelegate :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m ()
+ Test.Cleveland: registerDelegate :: (HasCallStack, MonadCleveland caps m) => ImplicitAddress -> m ()
- Test.Cleveland: resolveAddress :: (HasCallStack, MonadCleveland caps m) => Alias -> m Address
+ Test.Cleveland: resolveAddress :: (HasCallStack, MonadCleveland caps m) => Alias kind -> m (KindedAddress kind)
- Test.Cleveland: scenario :: ClevelandT m () -> Scenario m
+ Test.Cleveland: scenario :: MonadScenario m => ClevelandT m () -> Scenario' m
- Test.Cleveland: scenarioEmulated :: EmulatedT PureM () -> Scenario PureM
+ Test.Cleveland: scenarioEmulated :: EmulatedT PureM () -> Scenario' PureM
- Test.Cleveland: signBinary :: (HasCallStack, BytesLike bs, MonadCleveland caps m) => bs -> Address -> m (TSignature bs)
+ Test.Cleveland: signBinary :: (HasCallStack, BytesLike bs, MonadCleveland caps m) => bs -> ImplicitAddress -> m (TSignature bs)
- Test.Cleveland: signBytes :: (HasCallStack, MonadCleveland caps m) => ByteString -> Address -> m Signature
+ Test.Cleveland: signBytes :: (HasCallStack, MonadCleveland caps m) => ByteString -> ImplicitAddress -> m Signature
- Test.Cleveland: testScenario :: TestName -> (forall m. MonadFail m => Scenario m) -> TestTree
+ Test.Cleveland: testScenario :: TestName -> (forall m. Scenario m) -> TestTree
- Test.Cleveland: transfer :: (HasCallStack, MonadOps m) => TransferData -> m ()
+ Test.Cleveland: transfer :: forall addr r. (HasCallStack, TransferFunc ('Incomplete (InitialTransferMode addr)) 'TransferIgnoreResult 'HasNoAmount r, ToL1Address addr) => addr -> r
- Test.Cleveland: whenNetwork :: MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadCleveland caps1 m1) => m1 ()) -> m ()
+ Test.Cleveland: whenNetwork :: MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadNetwork caps1 m1) => m1 ()) -> m ()
- Test.Cleveland: withChainId :: ChainId -> Scenario PureM -> Scenario PureM
+ Test.Cleveland: withChainId :: ChainId -> Scenario' PureM -> Scenario' PureM
- Test.Cleveland: withInitialLevel :: Natural -> Scenario PureM -> Scenario PureM
+ Test.Cleveland: withInitialLevel :: Natural -> Scenario' PureM -> Scenario' PureM
- Test.Cleveland: withInitialNow :: Timestamp -> Scenario PureM -> Scenario PureM
+ Test.Cleveland: withInitialNow :: Timestamp -> Scenario' PureM -> Scenario' PureM
- Test.Cleveland: withMinBlockTime :: Natural -> Scenario PureM -> Scenario PureM
+ Test.Cleveland: withMinBlockTime :: Natural -> Scenario' PureM -> Scenario' PureM
- Test.Cleveland: withMoneybag :: MonadCleveland caps m => Address -> m a -> m a
+ Test.Cleveland: withMoneybag :: MonadCleveland caps m => ImplicitAddress -> m a -> m a
- Test.Cleveland: withSender :: MonadCleveland caps m => Address -> m a -> m a
+ Test.Cleveland: withSender :: MonadCleveland caps m => ImplicitAddress -> m a -> m a
- Test.Cleveland.Internal.Abstract: ClevelandMiscImpl :: (forall res. HasCallStack => IO res -> m res) -> (HasCallStack => Alias -> m Address) -> (HasCallStack => SpecificOrDefaultAlias -> m Address) -> (HasCallStack => SpecificOrDefaultAlias -> m Address) -> (HasCallStack => ByteString -> Address -> m Signature) -> (HasCallStack => Sender -> UntypedOriginateData -> m Address) -> (HasCallStack => Text -> m ()) -> (HasCallStack => Address -> m Mutez) -> (HasCallStack => Address -> m SomeAnnotatedValue) -> (forall k v. (HasCallStack, NiceComparable k, NicePackedValue k, NiceUnpackedValue v) => BigMapId k v -> k -> m (Maybe v)) -> (forall k v. (HasCallStack, NiceComparable k, NiceUnpackedValue v) => BigMapId k v -> m (Maybe [v])) -> (HasCallStack => Address -> m PublicKey) -> (HasCallStack => Address -> m (Maybe KeyHash)) -> (HasCallStack => Address -> m ()) -> (HasCallStack => m ChainId) -> (forall unit. (HasCallStack, KnownDivRat unit Second) => Time unit -> m ()) -> (HasCallStack => (Natural -> Natural) -> m ()) -> (HasCallStack => m Timestamp) -> (HasCallStack => m Natural) -> (forall a. HasCallStack => Builder -> m a) -> (forall a. HasCallStack => SomeException -> m a) -> (HasCallStack => m (Time Second)) -> (forall a e. (Exception e, HasCallStack) => m a -> m (Either e a)) -> (Address -> m ()) -> m (Maybe (EmulatedImpl m)) -> (forall cp st vd. (HasCallStack, HasRPCRepr st, IsoValue (AsRPC st)) => Sender -> RunCode cp st vd -> m (AsRPC st)) -> ClevelandMiscImpl m
+ Test.Cleveland.Internal.Abstract: ClevelandMiscImpl :: (forall res. HasCallStack => IO res -> m res) -> (forall kind. HasCallStack => Alias kind -> m (KindedAddress kind)) -> (HasCallStack => SpecificOrDefaultAlias -> m ImplicitAddress) -> (HasCallStack => SpecificOrDefaultAlias -> m ImplicitAddress) -> (HasCallStack => ByteString -> ImplicitAddress -> m Signature) -> (HasCallStack => Sender -> UntypedOriginateData 'IsLarge -> m ContractAddress) -> (HasCallStack => Text -> m ()) -> (HasCallStack => L1Address -> m Mutez) -> (HasCallStack => ContractAddress -> m SomeAnnotatedValue) -> (forall k v. (HasCallStack, NiceComparable k, NicePackedValue k, NiceUnpackedValue v) => BigMapId k v -> k -> m (Maybe v)) -> (forall k v. (HasCallStack, NiceComparable k, NiceUnpackedValue v) => BigMapId k v -> m (Maybe [v])) -> (HasCallStack => ImplicitAddress -> m PublicKey) -> (HasCallStack => ContractAddress -> m (Maybe KeyHash)) -> (HasCallStack => ImplicitAddress -> m ()) -> (HasCallStack => m ChainId) -> (forall unit. (HasCallStack, KnownDivRat unit Second) => Time unit -> m ()) -> (HasCallStack => (Natural -> Natural) -> m ()) -> (HasCallStack => m Timestamp) -> (HasCallStack => m Natural) -> (forall a. HasCallStack => Builder -> m a) -> (forall a. HasCallStack => SomeException -> m a) -> (HasCallStack => m (Time Second)) -> (forall a e. (Exception e, HasCallStack) => m a -> m (Either e a)) -> (ImplicitAddress -> m ()) -> m (Either (EmulatedImpl m) NetworkEnv) -> (forall cp st vd. (HasCallStack, HasRPCRepr st, IsoValue (AsRPC st)) => Sender -> RunCode cp st vd -> m (AsRPC st)) -> ClevelandMiscImpl m
- Test.Cleveland.Internal.Abstract: ClevelandOpsImpl :: (HasCallStack => [OperationInfo ClevelandInput] -> m [OperationInfo Result]) -> ClevelandOpsImpl m
+ Test.Cleveland.Internal.Abstract: ClevelandOpsImpl :: (HasCallStack => [OperationInfo ClevelandInput] -> m [OperationInfo ClevelandResult]) -> ClevelandOpsImpl m
- Test.Cleveland.Internal.Abstract: ContractHandle :: Text -> Address -> ContractHandle (cp :: Type) (st :: Type) (vd :: Type)
+ Test.Cleveland.Internal.Abstract: ContractHandle :: ContractAlias -> ContractAddress -> ContractHandle (cp :: Type) (st :: Type) (vd :: Type)
- Test.Cleveland.Internal.Abstract: Moneybag :: Address -> Moneybag
+ Test.Cleveland.Internal.Abstract: Moneybag :: ImplicitAddress -> Moneybag
- Test.Cleveland.Internal.Abstract: OriginateData :: Alias -> Mutez -> st -> Contract param st vd -> OriginateData param st vd
+ Test.Cleveland.Internal.Abstract: OriginateData :: ContractAlias -> Mutez -> st -> Contract param st vd -> OriginateData param st vd (large :: LargeOrigination)
- Test.Cleveland.Internal.Abstract: RunCode :: Contract cp st vd -> MaybeRPC st -> MaybeRPC cp -> Mutez -> Maybe Natural -> Maybe Timestamp -> Mutez -> Maybe Address -> RunCode cp st vd
+ Test.Cleveland.Internal.Abstract: RunCode :: Contract cp st vd -> Value -> Value -> Mutez -> Maybe Natural -> Maybe Timestamp -> Mutez -> Maybe ImplicitAddress -> RunCode cp st vd
- Test.Cleveland.Internal.Abstract: Sender :: Address -> Sender
+ Test.Cleveland.Internal.Abstract: Sender :: ImplicitAddress -> Sender
- Test.Cleveland.Internal.Abstract: SpecificAlias :: Alias -> SpecificOrDefaultAlias
+ Test.Cleveland.Internal.Abstract: SpecificAlias :: ImplicitAlias -> SpecificOrDefaultAlias
- Test.Cleveland.Internal.Abstract: TransferFailure :: Address -> TransferFailureReason -> TransferFailure
+ Test.Cleveland.Internal.Abstract: TransferFailure :: AddressAndAlias -> TransferFailureReason -> TransferFailure
- Test.Cleveland.Internal.Abstract: UntypedOriginateData :: Alias -> Mutez -> Value -> Contract -> UntypedOriginateData
+ Test.Cleveland.Internal.Abstract: UntypedOriginateData :: ContractAlias -> Mutez -> Value -> Contract -> UntypedOriginateData (large :: LargeOrigination)
- Test.Cleveland.Internal.Abstract: [chAddress] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> Address
+ Test.Cleveland.Internal.Abstract: [chAddress] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> ContractAddress
- Test.Cleveland.Internal.Abstract: [chContractName] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> Text
+ Test.Cleveland.Internal.Abstract: [chContractName] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> ContractAlias
- Test.Cleveland.Internal.Abstract: [cmiGenFreshKey] :: ClevelandMiscImpl m -> HasCallStack => SpecificOrDefaultAlias -> m Address
+ Test.Cleveland.Internal.Abstract: [cmiGenFreshKey] :: ClevelandMiscImpl m -> HasCallStack => SpecificOrDefaultAlias -> m ImplicitAddress
- Test.Cleveland.Internal.Abstract: [cmiGenKey] :: ClevelandMiscImpl m -> HasCallStack => SpecificOrDefaultAlias -> m Address
+ Test.Cleveland.Internal.Abstract: [cmiGenKey] :: ClevelandMiscImpl m -> HasCallStack => SpecificOrDefaultAlias -> m ImplicitAddress
- Test.Cleveland.Internal.Abstract: [cmiGetBalance] :: ClevelandMiscImpl m -> HasCallStack => Address -> m Mutez
+ Test.Cleveland.Internal.Abstract: [cmiGetBalance] :: ClevelandMiscImpl m -> HasCallStack => L1Address -> m Mutez
- Test.Cleveland.Internal.Abstract: [cmiGetDelegate] :: ClevelandMiscImpl m -> HasCallStack => Address -> m (Maybe KeyHash)
+ Test.Cleveland.Internal.Abstract: [cmiGetDelegate] :: ClevelandMiscImpl m -> HasCallStack => ContractAddress -> m (Maybe KeyHash)
- Test.Cleveland.Internal.Abstract: [cmiGetPublicKey] :: ClevelandMiscImpl m -> HasCallStack => Address -> m PublicKey
+ Test.Cleveland.Internal.Abstract: [cmiGetPublicKey] :: ClevelandMiscImpl m -> HasCallStack => ImplicitAddress -> m PublicKey
- Test.Cleveland.Internal.Abstract: [cmiGetSomeStorage] :: ClevelandMiscImpl m -> HasCallStack => Address -> m SomeAnnotatedValue
+ Test.Cleveland.Internal.Abstract: [cmiGetSomeStorage] :: ClevelandMiscImpl m -> HasCallStack => ContractAddress -> m SomeAnnotatedValue
- Test.Cleveland.Internal.Abstract: [cmiMarkAddressRefillable] :: ClevelandMiscImpl m -> Address -> m ()
+ Test.Cleveland.Internal.Abstract: [cmiMarkAddressRefillable] :: ClevelandMiscImpl m -> ImplicitAddress -> m ()
- Test.Cleveland.Internal.Abstract: [cmiOriginateLargeUntyped] :: ClevelandMiscImpl m -> HasCallStack => Sender -> UntypedOriginateData -> m Address
+ Test.Cleveland.Internal.Abstract: [cmiOriginateLargeUntyped] :: ClevelandMiscImpl m -> HasCallStack => Sender -> UntypedOriginateData 'IsLarge -> m ContractAddress
- Test.Cleveland.Internal.Abstract: [cmiRegisterDelegate] :: ClevelandMiscImpl m -> HasCallStack => Address -> m ()
+ Test.Cleveland.Internal.Abstract: [cmiRegisterDelegate] :: ClevelandMiscImpl m -> HasCallStack => ImplicitAddress -> m ()
- Test.Cleveland.Internal.Abstract: [cmiResolveAddress] :: ClevelandMiscImpl m -> HasCallStack => Alias -> m Address
+ Test.Cleveland.Internal.Abstract: [cmiResolveAddress] :: ClevelandMiscImpl m -> forall kind. HasCallStack => Alias kind -> m (KindedAddress kind)
- Test.Cleveland.Internal.Abstract: [cmiSignBytes] :: ClevelandMiscImpl m -> HasCallStack => ByteString -> Address -> m Signature
+ Test.Cleveland.Internal.Abstract: [cmiSignBytes] :: ClevelandMiscImpl m -> HasCallStack => ByteString -> ImplicitAddress -> m Signature
- Test.Cleveland.Internal.Abstract: [coiRunOperationBatch] :: ClevelandOpsImpl m -> HasCallStack => [OperationInfo ClevelandInput] -> m [OperationInfo Result]
+ Test.Cleveland.Internal.Abstract: [coiRunOperationBatch] :: ClevelandOpsImpl m -> HasCallStack => [OperationInfo ClevelandInput] -> m [OperationInfo ClevelandResult]
- Test.Cleveland.Internal.Abstract: [odBalance] :: OriginateData param st vd -> Mutez
+ Test.Cleveland.Internal.Abstract: [odBalance] :: OriginateData param st vd (large :: LargeOrigination) -> Mutez
- Test.Cleveland.Internal.Abstract: [odContract] :: OriginateData param st vd -> Contract param st vd
+ Test.Cleveland.Internal.Abstract: [odContract] :: OriginateData param st vd (large :: LargeOrigination) -> Contract param st vd
- Test.Cleveland.Internal.Abstract: [odName] :: OriginateData param st vd -> Alias
+ Test.Cleveland.Internal.Abstract: [odName] :: OriginateData param st vd (large :: LargeOrigination) -> ContractAlias
- Test.Cleveland.Internal.Abstract: [odStorage] :: OriginateData param st vd -> st
+ Test.Cleveland.Internal.Abstract: [odStorage] :: OriginateData param st vd (large :: LargeOrigination) -> st
- Test.Cleveland.Internal.Abstract: [rcParameter] :: RunCode cp st vd -> MaybeRPC cp
+ Test.Cleveland.Internal.Abstract: [rcParameter] :: RunCode cp st vd -> Value
- Test.Cleveland.Internal.Abstract: [rcSource] :: RunCode cp st vd -> Maybe Address
+ Test.Cleveland.Internal.Abstract: [rcSource] :: RunCode cp st vd -> Maybe ImplicitAddress
- Test.Cleveland.Internal.Abstract: [rcStorage] :: RunCode cp st vd -> MaybeRPC st
+ Test.Cleveland.Internal.Abstract: [rcStorage] :: RunCode cp st vd -> Value
- Test.Cleveland.Internal.Abstract: [unMoneybag] :: Moneybag -> Address
+ Test.Cleveland.Internal.Abstract: [unMoneybag] :: Moneybag -> ImplicitAddress
- Test.Cleveland.Internal.Abstract: [unSender] :: Sender -> Address
+ Test.Cleveland.Internal.Abstract: [unSender] :: Sender -> ImplicitAddress
- Test.Cleveland.Internal.Abstract: [uodBalance] :: UntypedOriginateData -> Mutez
+ Test.Cleveland.Internal.Abstract: [uodBalance] :: UntypedOriginateData (large :: LargeOrigination) -> Mutez
- Test.Cleveland.Internal.Abstract: [uodContract] :: UntypedOriginateData -> Contract
+ Test.Cleveland.Internal.Abstract: [uodContract] :: UntypedOriginateData (large :: LargeOrigination) -> Contract
- Test.Cleveland.Internal.Abstract: [uodName] :: UntypedOriginateData -> Alias
+ Test.Cleveland.Internal.Abstract: [uodName] :: UntypedOriginateData (large :: LargeOrigination) -> ContractAlias
- Test.Cleveland.Internal.Abstract: [uodStorage] :: UntypedOriginateData -> Value
+ Test.Cleveland.Internal.Abstract: [uodStorage] :: UntypedOriginateData (large :: LargeOrigination) -> Value
- Test.Cleveland.Internal.Abstract: data Alias
+ Test.Cleveland.Internal.Abstract: data Alias (kind :: AddressKind)
- Test.Cleveland.Internal.Abstract: data OriginateData param st vd
+ Test.Cleveland.Internal.Abstract: data OriginateData param st vd (large :: LargeOrigination)
- Test.Cleveland.Internal.Abstract: data UntypedOriginateData
+ Test.Cleveland.Internal.Abstract: data UntypedOriginateData (large :: LargeOrigination)
- Test.Cleveland.Internal.Abstract: ep :: HasCallStack => Text -> EpName
+ Test.Cleveland.Internal.Abstract: ep :: EntrypointNameConstructor epName a => a
- Test.Cleveland.Internal.Abstract: mkDefaultAlias :: Natural -> Alias
+ Test.Cleveland.Internal.Abstract: mkDefaultAlias :: Natural -> ImplicitAlias
- Test.Cleveland.Internal.Abstract: runOperationBatchM :: (HasCallStack, Buildable e, Functor m) => Proxy e -> ClevelandOpsImpl m -> BatchingM (OperationInfo ClevelandInput) (OperationInfo Result) e a -> m a
+ Test.Cleveland.Internal.Abstract: runOperationBatchM :: (HasCallStack, Buildable e, Functor m) => Proxy e -> ClevelandOpsImpl m -> BatchingM (OperationInfo ClevelandInput) (OperationInfo ClevelandResult) e a -> m a
- Test.Cleveland.Internal.Abstract: runSingleOperation :: (HasCallStack, Functor m) => ClevelandOpsImpl m -> Text -> OperationInfo ClevelandInput -> (OperationInfo Result -> Maybe a) -> m a
+ Test.Cleveland.Internal.Abstract: runSingleOperation :: (HasCallStack, Functor m) => ClevelandOpsImpl m -> Text -> OperationInfo ClevelandInput -> (OperationInfo ClevelandResult -> Maybe a) -> m a
- Test.Cleveland.Internal.Actions: class Functor m => MonadOps m
+ Test.Cleveland.Internal.Actions: class (MonadTransfer m, MonadOriginate m) => MonadOps m
- Test.Cleveland.Internal.Actions: enumAliases :: forall n n'. (SingIPeano n, IsoNatPeano n n') => Alias -> SizedList n SpecificOrDefaultAlias
+ Test.Cleveland.Internal.Actions: enumAliases :: forall n n'. (SingIPeano n, IsoNatPeano n n') => ImplicitAlias -> SizedList n SpecificOrDefaultAlias
- Test.Cleveland.Internal.Actions: getBalance :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m Mutez
+ Test.Cleveland.Internal.Actions: getBalance :: (HasCallStack, MonadCleveland caps m, ToL1Address addr) => addr -> m Mutez
- Test.Cleveland.Internal.Actions: getDelegate :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m (Maybe KeyHash)
+ Test.Cleveland.Internal.Actions: getDelegate :: (HasCallStack, MonadCleveland caps m, ToContractAddress addr) => addr -> m (Maybe KeyHash)
- Test.Cleveland.Internal.Actions: getPublicKey :: (HasCallStack, MonadCleveland caps m) => Address -> m PublicKey
+ Test.Cleveland.Internal.Actions: getPublicKey :: (HasCallStack, MonadCleveland caps m) => ImplicitAddress -> m PublicKey
- Test.Cleveland.Internal.Actions: getSomeStorage :: forall addr caps m. (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m SomeAnnotatedValue
+ Test.Cleveland.Internal.Actions: getSomeStorage :: forall addr caps m. (HasCallStack, MonadCleveland caps m, ToContractAddress addr) => addr -> m SomeAnnotatedValue
- Test.Cleveland.Internal.Actions: ifEmulation :: forall a caps m. MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadEmulated caps1 m1) => m1 a) -> (forall caps1 m1. (EqBaseMonad caps caps1, MonadCleveland caps1 m1) => m1 a) -> m a
+ Test.Cleveland.Internal.Actions: ifEmulation :: forall a caps m. MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadEmulated caps1 m1) => m1 a) -> (forall caps1 m1. (EqBaseMonad caps caps1, MonadNetwork caps1 m1) => m1 a) -> m a
- Test.Cleveland.Internal.Actions: newAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m Address
+ Test.Cleveland.Internal.Actions: newAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m ImplicitAddress
- Test.Cleveland.Internal.Actions: newAddresses :: forall n n' caps m. (HasCallStack, MonadCleveland caps m, IsoNatPeano n n') => SizedList n SpecificOrDefaultAlias -> m (SizedList n Address)
+ Test.Cleveland.Internal.Actions: newAddresses :: forall n n' caps m. (HasCallStack, MonadCleveland caps m, IsoNatPeano n n') => SizedList n SpecificOrDefaultAlias -> m (SizedList n ImplicitAddress)
- Test.Cleveland.Internal.Actions: newFreshAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m Address
+ Test.Cleveland.Internal.Actions: newFreshAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m ImplicitAddress
- Test.Cleveland.Internal.Actions: originate :: forall cp st vd m. (HasCallStack, MonadOps m) => OriginateData cp st vd -> m (ContractHandle cp st vd)
+ Test.Cleveland.Internal.Actions: originate :: forall contract r. (HasCallStack, OriginateFunc contract 'NoBalance 'NotLarge r) => ContractAlias -> ContractStorage contract -> contract -> r
- Test.Cleveland.Internal.Actions: refillable :: MonadCleveland caps m => m Address -> m Address
+ Test.Cleveland.Internal.Actions: refillable :: MonadCleveland caps m => m ImplicitAddress -> m ImplicitAddress
- Test.Cleveland.Internal.Actions: registerDelegate :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m ()
+ Test.Cleveland.Internal.Actions: registerDelegate :: (HasCallStack, MonadCleveland caps m) => ImplicitAddress -> m ()
- Test.Cleveland.Internal.Actions: resolveAddress :: (HasCallStack, MonadCleveland caps m) => Alias -> m Address
+ Test.Cleveland.Internal.Actions: resolveAddress :: (HasCallStack, MonadCleveland caps m) => Alias kind -> m (KindedAddress kind)
- Test.Cleveland.Internal.Actions: signBinary :: (HasCallStack, BytesLike bs, MonadCleveland caps m) => bs -> Address -> m (TSignature bs)
+ Test.Cleveland.Internal.Actions: signBinary :: (HasCallStack, BytesLike bs, MonadCleveland caps m) => bs -> ImplicitAddress -> m (TSignature bs)
- Test.Cleveland.Internal.Actions: signBytes :: (HasCallStack, MonadCleveland caps m) => ByteString -> Address -> m Signature
+ Test.Cleveland.Internal.Actions: signBytes :: (HasCallStack, MonadCleveland caps m) => ByteString -> ImplicitAddress -> m Signature
- Test.Cleveland.Internal.Actions: transfer :: (HasCallStack, MonadOps m) => TransferData -> m ()
+ Test.Cleveland.Internal.Actions: transfer :: forall addr r. (HasCallStack, TransferFunc ('Incomplete (InitialTransferMode addr)) 'TransferIgnoreResult 'HasNoAmount r, ToL1Address addr) => addr -> r
- Test.Cleveland.Internal.Actions: whenNetwork :: MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadCleveland caps1 m1) => m1 ()) -> m ()
+ Test.Cleveland.Internal.Actions: whenNetwork :: MonadCleveland caps m => (forall caps1 m1. (EqBaseMonad caps caps1, MonadNetwork caps1 m1) => m1 ()) -> m ()
- Test.Cleveland.Internal.Actions: withMoneybag :: MonadCleveland caps m => Address -> m a -> m a
+ Test.Cleveland.Internal.Actions: withMoneybag :: MonadCleveland caps m => ImplicitAddress -> m a -> m a
- Test.Cleveland.Internal.Actions: withSender :: MonadCleveland caps m => Address -> m a -> m a
+ Test.Cleveland.Internal.Actions: withSender :: MonadCleveland caps m => ImplicitAddress -> m a -> m a
- Test.Cleveland.Internal.Client: ClientState :: DefaultAliasCounter -> Set Address -> Moneybag -> ClientState
+ Test.Cleveland.Internal.Client: ClientState :: DefaultAliasCounter -> Set ImplicitAddress -> Moneybag -> ClientState
- Test.Cleveland.Internal.Client: NoMoneybagAddress :: Alias -> MoneybagConfigurationException
+ Test.Cleveland.Internal.Client: NoMoneybagAddress :: ImplicitAlias -> MoneybagConfigurationException
- Test.Cleveland.Internal.Client: TooManyRefillIterations :: Word -> Address -> InternalNetworkScenarioError
+ Test.Cleveland.Internal.Client: TooManyRefillIterations :: Word -> ImplicitAddress -> InternalNetworkScenarioError
- Test.Cleveland.Internal.Client: TwoMoneybagKeys :: Alias -> SecretKey -> Address -> MoneybagConfigurationException
+ Test.Cleveland.Internal.Client: TwoMoneybagKeys :: ImplicitAlias -> SecretKey -> ImplicitAddress -> MoneybagConfigurationException
- Test.Cleveland.Internal.Client: [csRefillableAddresses] :: ClientState -> Set Address
+ Test.Cleveland.Internal.Client: [csRefillableAddresses] :: ClientState -> Set ImplicitAddress
- Test.Cleveland.Internal.Client: neMoneybagAliasL :: Lens' NetworkEnv Alias
+ Test.Cleveland.Internal.Client: neMoneybagAliasL :: Lens' NetworkEnv ImplicitAlias
- Test.Cleveland.Internal.Client: networkMiscImpl :: MorleyClientEnv -> ClevelandMiscImpl ClientM
+ Test.Cleveland.Internal.Client: networkMiscImpl :: NetworkEnv -> ClevelandMiscImpl ClientM
- Test.Cleveland.Internal.Client: revealKeyUnlessRevealed :: MorleyClientEnv -> Address -> IO ()
+ Test.Cleveland.Internal.Client: revealKeyUnlessRevealed :: MorleyClientEnv -> ImplicitAddress -> IO ()
- Test.Cleveland.Internal.Pure: initEnv :: Alias -> PureState
+ Test.Cleveland.Internal.Pure: initEnv :: ImplicitAlias -> PureState
- Test.Cleveland.Internal.Pure: moneybagAlias :: Alias
+ Test.Cleveland.Internal.Pure: moneybagAlias :: ImplicitAlias
- Test.Cleveland.Internal.Pure: psRefillableAddresses :: Lens' PureState (Set Address)
+ Test.Cleveland.Internal.Pure: psRefillableAddresses :: Lens' PureState (Set ImplicitAddress)
- Test.Cleveland.Internal.Pure: runEmulatedT :: Alias -> EmulatedT PureM a -> IO a
+ Test.Cleveland.Internal.Pure: runEmulatedT :: ImplicitAlias -> EmulatedT PureM a -> IO a
- Test.Cleveland.Internal.Scenario: [ScenarioEmulated] :: EmulatedT PureM () -> Scenario PureM
+ Test.Cleveland.Internal.Scenario: [ScenarioEmulated] :: EmulatedT PureM () -> Scenario' PureM
- Test.Cleveland.Internal.Scenario: scenario :: ClevelandT m () -> Scenario m
+ Test.Cleveland.Internal.Scenario: scenario :: MonadScenario m => ClevelandT m () -> Scenario' m
- Test.Cleveland.Internal.Scenario: scenarioEmulated :: EmulatedT PureM () -> Scenario PureM
+ Test.Cleveland.Internal.Scenario: scenarioEmulated :: EmulatedT PureM () -> Scenario' PureM
- Test.Cleveland.Internal.Scenario: withChainId :: ChainId -> Scenario PureM -> Scenario PureM
+ Test.Cleveland.Internal.Scenario: withChainId :: ChainId -> Scenario' PureM -> Scenario' PureM
- Test.Cleveland.Internal.Scenario: withInitialLevel :: Natural -> Scenario PureM -> Scenario PureM
+ Test.Cleveland.Internal.Scenario: withInitialLevel :: Natural -> Scenario' PureM -> Scenario' PureM
- Test.Cleveland.Internal.Scenario: withInitialNow :: Timestamp -> Scenario PureM -> Scenario PureM
+ Test.Cleveland.Internal.Scenario: withInitialNow :: Timestamp -> Scenario' PureM -> Scenario' PureM
- Test.Cleveland.Internal.Scenario: withMinBlockTime :: Natural -> Scenario PureM -> Scenario PureM
+ Test.Cleveland.Internal.Scenario: withMinBlockTime :: Natural -> Scenario' PureM -> Scenario' PureM
- Test.Cleveland.Lorentz: ContractHandle :: Text -> Address -> ContractHandle (cp :: Type) (st :: Type) (vd :: Type)
+ Test.Cleveland.Lorentz: ContractHandle :: ContractAlias -> ContractAddress -> ContractHandle (cp :: Type) (st :: Type) (vd :: Type)
- Test.Cleveland.Lorentz: [chAddress] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> Address
+ Test.Cleveland.Lorentz: [chAddress] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> ContractAddress
- Test.Cleveland.Lorentz: [chContractName] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> Text
+ Test.Cleveland.Lorentz: [chContractName] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> ContractAlias
- Test.Cleveland.Lorentz: class ToAddress addr => ToStorageType st addr
+ Test.Cleveland.Lorentz: class ToContractAddress addr => ToStorageType st addr
- Test.Cleveland.Lorentz.Ticketer: callViaTicketer :: forall targetArg payload td targetAddr ticketerParam ticketerAddr m. (HasCallStack, MonadOps m, ticketerParam ~ View_ (payload, (Natural, td)) targetArg, ToTAddress ticketerParam () ticketerAddr, ToContractRef targetArg targetAddr, NiceParameterFull ticketerParam) => ticketerAddr -> Natural -> td -> targetAddr -> payload -> m ()
+ Test.Cleveland.Lorentz.Ticketer: callViaTicketer :: forall targetArg payload td targetAddr ticketerParam ticketerAddr m. (HasCallStack, MonadTransfer m, ticketerParam ~ View_ (payload, (Natural, td)) targetArg, ToL1TAddress ticketerParam () ticketerAddr, ToContractRef targetArg targetAddr, NiceParameterFull ticketerParam) => ticketerAddr -> Natural -> td -> targetAddr -> payload -> m ()
- Test.Cleveland.Lorentz.Types: ContractHandle :: Text -> Address -> ContractHandle (cp :: Type) (st :: Type) (vd :: Type)
+ Test.Cleveland.Lorentz.Types: ContractHandle :: ContractAlias -> ContractAddress -> ContractHandle (cp :: Type) (st :: Type) (vd :: Type)
- Test.Cleveland.Lorentz.Types: [chAddress] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> Address
+ Test.Cleveland.Lorentz.Types: [chAddress] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> ContractAddress
- Test.Cleveland.Lorentz.Types: [chContractName] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> Text
+ Test.Cleveland.Lorentz.Types: [chContractName] :: ContractHandle (cp :: Type) (st :: Type) (vd :: Type) -> ContractAlias
- Test.Cleveland.Lorentz.Types: class ToAddress addr => ToStorageType st addr
+ Test.Cleveland.Lorentz.Types: class ToContractAddress addr => ToStorageType st addr
- Test.Cleveland.Tasty: testScenario :: TestName -> (forall m. MonadFail m => Scenario m) -> TestTree
+ Test.Cleveland.Tasty: testScenario :: TestName -> (forall m. Scenario m) -> TestTree
- Test.Cleveland.Tasty.Internal: testScenario :: TestName -> (forall m. MonadFail m => Scenario m) -> TestTree
+ Test.Cleveland.Tasty.Internal: testScenario :: TestName -> (forall m. Scenario m) -> TestTree
- Test.Cleveland.Tasty.Internal.Options: MoneybagAliasOpt :: Alias -> MoneybagAliasOpt
+ Test.Cleveland.Tasty.Internal.Options: MoneybagAliasOpt :: ImplicitAlias -> MoneybagAliasOpt
Files
- CHANGES.md +34/−0
- cleveland.cabal +16/−1
- src/Hedgehog/Gen/Michelson/Typed.hs +4/−4
- src/Hedgehog/Gen/Tezos/Address.hs +5/−5
- src/Test/Cleveland.hs +30/−15
- src/Test/Cleveland/Instances.hs +18/−3
- src/Test/Cleveland/Internal/Abstract.hs +192/−52
- src/Test/Cleveland/Internal/Actions.hs +120/−1251
- src/Test/Cleveland/Internal/Actions/Assertions.hs +125/−0
- src/Test/Cleveland/Internal/Actions/ExceptionHandling.hs +188/−0
- src/Test/Cleveland/Internal/Actions/Helpers.hs +12/−0
- src/Test/Cleveland/Internal/Actions/Misc.hs +552/−0
- src/Test/Cleveland/Internal/Actions/MonadOps.hs +38/−0
- src/Test/Cleveland/Internal/Actions/Originate.hs +225/−0
- src/Test/Cleveland/Internal/Actions/Transfer.hs +331/−0
- src/Test/Cleveland/Internal/Actions/TransferFailurePredicate.hs +137/−0
- src/Test/Cleveland/Internal/Client.hs +142/−128
- src/Test/Cleveland/Internal/Hedgehog.hs +1/−3
- src/Test/Cleveland/Internal/Pure.hs +200/−238
- src/Test/Cleveland/Internal/Scenario.hs +47/−25
- src/Test/Cleveland/Lorentz.hs +3/−0
- src/Test/Cleveland/Lorentz/Ticketer.hs +6/−5
- src/Test/Cleveland/Lorentz/Types.hs +55/−5
- src/Test/Cleveland/Tasty/Internal.hs +15/−18
- src/Test/Cleveland/Tasty/Internal/Options.hs +4/−4
- src/Test/Cleveland/Util.hs +1/−1
- test/TestSuite/Cleveland/AddressRevealing.hs +2/−2
- test/TestSuite/Cleveland/BadAddressReuse.hs +21/−0
- test/TestSuite/Cleveland/BalanceCheck.hs +4/−4
- test/TestSuite/Cleveland/BatchOperation.hs +7/−8
- test/TestSuite/Cleveland/BatchTransferCheck.hs +4/−4
- test/TestSuite/Cleveland/BytesSigning.hs +3/−3
- test/TestSuite/Cleveland/CallStack.hs +57/−86
- test/TestSuite/Cleveland/ChainIdGet.hs +2/−2
- test/TestSuite/Cleveland/ContractAllocation.hs +5/−12
- test/TestSuite/Cleveland/DFS.hs +6/−12
- test/TestSuite/Cleveland/EmitMachinery.hs +62/−0
- test/TestSuite/Cleveland/EmptyImplicitAddress.hs +3/−3
- test/TestSuite/Cleveland/Emulated.hs +7/−7
- test/TestSuite/Cleveland/ErrorMessages.hs +18/−0
- test/TestSuite/Cleveland/ExpectFailure.hs +39/−51
- test/TestSuite/Cleveland/FailureLogs.hs +5/−5
- test/TestSuite/Cleveland/Import.hs +7/−7
- test/TestSuite/Cleveland/NetworkCaps.hs +18/−0
- test/TestSuite/Cleveland/NewAddressCheck.hs +1/−1
- test/TestSuite/Cleveland/OperationReplay.hs +5/−5
- test/TestSuite/Cleveland/PrettyFailWith.hs +3/−3
- test/TestSuite/Cleveland/PublicKeyToAddress.hs +8/−10
- test/TestSuite/Cleveland/RefillableAddress.hs +8/−13
- test/TestSuite/Cleveland/ResolveAddress.hs +28/−0
- test/TestSuite/Cleveland/RunCode.hs +79/−77
- test/TestSuite/Cleveland/StorageCheck.hs +13/−16
- test/TestSuite/Cleveland/StorageWithBigMaps.hs +24/−24
- test/TestSuite/Cleveland/Tasty/Report.hs +2/−2
- test/TestSuite/Cleveland/Tasty/Report/Examples.hs +2/−2
- test/TestSuite/Cleveland/TransferCheck.hs +8/−71
- test/TestSuite/Cleveland/VotingPower.hs +4/−4
- test/TestSuite/Cleveland/WithMoneybag.hs +1/−1
- test/TestSuite/Cleveland/WithSender.hs +8/−8
CHANGES.md view
@@ -1,6 +1,40 @@ <!-- Unreleased: append new entries here --> +0.2.1+=====+* [!1199](https://gitlab.com/morley-framework/morley/-/merge_requests/1199)+ Replace removed HasTezosClient actions with TezosClient.Impl version.+* [!1212](https://gitlab.com/morley-framework/morley/-/merge_requests/1212)+ Support contract events+ + Untie cleveland operation results from morley-client.+ + Introduce `ContractEvent` type for contract events.+ + Introduce new `WithContractEvents` flag for `transfer`, which tells it to+ return `[ContractEvent]`.+* [!1191](https://gitlab.com/morley-framework/morley/-/merge_requests/1191)+ General cleanup+ + Display contract's aliases in error messages when a transfer fails (emulator-mode only).+* [!1177](https://gitlab.com/morley-framework/morley/-/merge_requests/1177)+ Distinguish implicit/contract aliases and addresses on the type level+* [!1187](https://gitlab.com/morley-framework/morley/-/merge_requests/1187)+ Access MorleyClientEnv in network tests+ + Add `NetworkCaps` carrying `NetworkEnv`.+ + Replace `ScenarioCleveland` with `ScenarioNetwork`.+ + Reimplement `scenario` as a function in `MonadScenario` typeclass.+ + Rename `Scenario` to `Scenario'`, add `Scenario` synonym that bakes in+ `MonadScenario` constraint.+ + Allow `ifEmulation` to access `NetworkCaps` in the on-network branch.+* [!1168](https://gitlab.com/morley-framework/morley/-/merge_requests/1168)+ Support a mix of RPC and non-RPC representations in `runCode`+* [!1137](https://gitlab.com/morley-framework/morley/-/merge_requests/1137)+ Refactor Cleveland's originate\* and `transfer`/`transferMoney`/`call`+ functions+ + All 9 `originate*` functions are replaced with single `originate`,+ optionally accepting initial balance (as `Mutez`) and whether it's a large+ origination (using `Large` argument).+ + `transfer`, `transferMoney` and `call` functions replaced by `transfer` and+ two helpers, `calling` and `unsafeCalling`.+ 0.2.0 ===== * [!1172](https://gitlab.com/morley-framework/morley/-/merge_requests/1172)
cleveland.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: cleveland-version: 0.2.0+version: 0.2.1 synopsis: Testing framework for Morley. description: This package provides an eDSL for testing contracts written in Michelson, Morley or Lorentz. These tests can be run on an emulated environment or on a real network. category: Blockchain@@ -58,6 +58,14 @@ Test.Cleveland.Instances Test.Cleveland.Internal.Abstract Test.Cleveland.Internal.Actions+ Test.Cleveland.Internal.Actions.Assertions+ Test.Cleveland.Internal.Actions.ExceptionHandling+ Test.Cleveland.Internal.Actions.Helpers+ Test.Cleveland.Internal.Actions.Misc+ Test.Cleveland.Internal.Actions.MonadOps+ Test.Cleveland.Internal.Actions.Originate+ Test.Cleveland.Internal.Actions.Transfer+ Test.Cleveland.Internal.Actions.TransferFailurePredicate Test.Cleveland.Internal.Client Test.Cleveland.Internal.Exceptions Test.Cleveland.Internal.Hedgehog@@ -108,6 +116,7 @@ GADTs GeneralizedNewtypeDeriving ImportQualifiedPost+ InstanceSigs LambdaCase MultiParamTypeClasses MultiWayIf@@ -187,6 +196,7 @@ other-modules: TestSuite.Cleveland.AddressRevealing TestSuite.Cleveland.Assertions+ TestSuite.Cleveland.BadAddressReuse TestSuite.Cleveland.BalanceCheck TestSuite.Cleveland.BatchOperation TestSuite.Cleveland.BatchTransferCheck@@ -196,9 +206,11 @@ TestSuite.Cleveland.ChainIdGet TestSuite.Cleveland.ContractAllocation TestSuite.Cleveland.DFS+ TestSuite.Cleveland.EmitMachinery TestSuite.Cleveland.EmptyImplicitAddress TestSuite.Cleveland.Emulated TestSuite.Cleveland.Entrypoints+ TestSuite.Cleveland.ErrorMessages TestSuite.Cleveland.ExpectFailure TestSuite.Cleveland.FailureLogs TestSuite.Cleveland.Import@@ -207,11 +219,13 @@ TestSuite.Cleveland.Lorentz.Contracts.ContractAllocator TestSuite.Cleveland.Lorentz.Entrypoints TestSuite.Cleveland.MismatchError+ TestSuite.Cleveland.NetworkCaps TestSuite.Cleveland.NewAddressCheck TestSuite.Cleveland.OperationReplay TestSuite.Cleveland.PrettyFailWith TestSuite.Cleveland.PublicKeyToAddress TestSuite.Cleveland.RefillableAddress+ TestSuite.Cleveland.ResolveAddress TestSuite.Cleveland.RunCode TestSuite.Cleveland.StorageCheck TestSuite.Cleveland.StorageWithBigMaps@@ -253,6 +267,7 @@ GADTs GeneralizedNewtypeDeriving ImportQualifiedPost+ InstanceSigs LambdaCase MultiParamTypeClasses MultiWayIf
src/Hedgehog/Gen/Michelson/Typed.hs view
@@ -34,7 +34,7 @@ import Hedgehog.Range qualified as Range import Hedgehog.Gen.Michelson.Untyped (genEpName)-import Hedgehog.Gen.Tezos.Address (genAddress)+import Hedgehog.Gen.Tezos.Address import Hedgehog.Gen.Tezos.Core (genChainId, genMutez, genTimestamp) import Hedgehog.Gen.Tezos.Crypto (genKeyHash, genPublicKey, genSignature) import Hedgehog.Gen.Tezos.Crypto.BLS12381 (genBls12381Fr, genBls12381G1, genBls12381G2)@@ -45,7 +45,7 @@ import Morley.Michelson.Typed.Haskell.Value (BigMap(..), BigMapId(..), ToT, WellTypedToT) import Morley.Michelson.Typed.Scope import Morley.Michelson.Typed.Value (RemFail(..))-import Morley.Tezos.Address (TxRollupL2Address(..))+import Morley.Tezos.Address (ConstrainedAddress(..), TxRollupL2Address(..)) import Morley.Tezos.Core (Mutez, Timestamp) import Morley.Tezos.Crypto (parseHash) import Morley.Tezos.Crypto.BLS12381 qualified as BLS@@ -79,7 +79,7 @@ <*> Gen.map (unLength <$> len) (liftA2 (,) genKey genVal) genEpAddress :: (MonadGen m, GenBase m ~ Identity) => m EpAddress-genEpAddress = EpAddress <$> genAddress <*> genEpName+genEpAddress = EpAddress' <$> genAddress <*> genEpName genValueKeyHash :: MonadGen m => m (Value' instr 'TKeyHash) genValueKeyHash = VKeyHash <$> genKeyHash@@ -128,7 +128,7 @@ genValueTicket :: (MonadGen m, Comparable a) => Range TicketAmount -> m (Value' instr a) -> m (Value' instr ('TTicket a))-genValueTicket range genVal = VTicket <$> genAddress <*> genVal+genValueTicket range genVal = VTicket . MkAddress <$> genContractAddress <*> genVal <*> Gen.integral (unTicketAmount <$> range) genValueChestAndKey :: MonadGen m => m (Value' instr 'TChest, Value' instr 'TChestKey)
src/Hedgehog/Gen/Tezos/Address.hs view
@@ -14,14 +14,14 @@ import Hedgehog.Range qualified as Range import Hedgehog.Gen.Tezos.Crypto (genKeyHash)-import Morley.Tezos.Address (Address(..))+import Morley.Tezos.Address import Morley.Tezos.Crypto genAddress :: MonadGen m => m Address-genAddress = Gen.choice [genKeyAddress, genContractAddress]+genAddress = Gen.choice [MkAddress <$> genKeyAddress, MkAddress <$> genContractAddress] -genKeyAddress :: MonadGen m => m Address-genKeyAddress = KeyAddress <$> genKeyHash+genKeyAddress :: MonadGen m => m ImplicitAddress+genKeyAddress = ImplicitAddress <$> genKeyHash -genContractAddress :: MonadGen m => m Address+genContractAddress :: MonadGen m => m ContractAddress genContractAddress = ContractAddress . Hash HashContract <$> Gen.bytes (Range.singleton 20)
src/Test/Cleveland.hs view
@@ -7,12 +7,17 @@ -- for usage instructions. module Test.Cleveland ( Alias+ , ContractAlias+ , ImplicitAlias+ , KindedAddress+ , ContractAddress+ , ImplicitAddress , ContractHandle (..)- , OriginateData (..)- , UntypedOriginateData (..) , TransferData (..)+ , TypedContract (..) , Scenario , PureM+ , ClientM -- * Validation , TransferFailure@@ -20,7 +25,9 @@ -- * Real network implementation based on @tezos-client@ and RPC. , testScenario , testScenarioOnNetwork- , scenario+ , scenarioNetwork+ , MonadScenario(..)+ , getMorleyClientEnv -- * Emulation tests , testScenarioOnEmulator@@ -50,17 +57,13 @@ , signBytes , signBinary , originate- , originateSimple- , originateUntyped- , originateUntypedSimple- , originateTypedSimple- , originateLarge- , originateLargeSimple- , originateLargeUntyped- , originateLargeUntypedSimple+ , Large (..) , transfer- , transferMoney- , call+ , WithContractEvents (..)+ , ContractEvent (..)+ , calling+ , Default(def)+ , unsafeCalling , importUntypedContract , importContract , noViews@@ -89,7 +92,6 @@ , getApproximateBlockInterval , getMinBlockTime , RunCode(..)- , AsRPC.MaybeRPC(..) , runCode , branchout , offshoot@@ -99,9 +101,16 @@ , ifEmulation , inBatch + -- * Address conversions+ , ToAddress(..)+ , ToL1Address(..)+ , ToL1TAddress(..)+ -- * Primitives re-exports , EntrypointRef (..) , VotingPowers+ , Mutez+ , tz , mkVotingPowers , mkVotingPowersFromMap @@ -153,6 +162,8 @@ , pattern DefEpName , ep , (?-)+ , (:!)+ , NamedF (..) -- * Integration with @hedgehog@ , testScenarioProps@@ -178,12 +189,15 @@ , forEach ) where -import Lorentz (EntrypointRef(..), pattern DefEpName)+import Data.Default (Default(def))++import Lorentz (EntrypointRef(..), Mutez, ToAddress(..), pattern DefEpName, tz) import Morley.AsRPC qualified as AsRPC import Morley.Client (MorleyClientEnv, MorleyClientEnv'(..)) import Morley.Client.TezosClient.Types (TezosClientEnv(..)) import Morley.Michelson.Interpret (MorleyLogs) import Morley.Michelson.Runtime (VotingPowers, mkVotingPowers, mkVotingPowersFromMap)+import Morley.Util.Named import Test.Cleveland.Instances () import Test.Cleveland.Internal.Abstract import Test.Cleveland.Internal.Actions@@ -191,5 +205,6 @@ import Test.Cleveland.Internal.Hedgehog import Test.Cleveland.Internal.Pure import Test.Cleveland.Internal.Scenario+import Test.Cleveland.Lorentz (ToL1Address(..), ToL1TAddress(..)) import Test.Cleveland.Tasty.Internal import Test.Cleveland.Util
src/Test/Cleveland/Instances.hs view
@@ -7,17 +7,20 @@ ( HasErrorSrcPos (..) ) where +import Data.Default (Default(..)) import Fmt (Buildable(..), eitherF, hexF, tupleF, (+|), (|+)) import GHC.Num qualified (fromInteger) import Test.Tasty.Runners (FailureReason(..)) import Time (Time) +import Lorentz.Entrypoints.Core (EntrypointRef(..), NiceEntrypointName) import Morley.Michelson.Text (MText, mkMText) import Morley.Michelson.Typed.Haskell.Value (BigMap(..)) import Morley.Michelson.Untyped qualified as U import Morley.Michelson.Untyped.Annotation (Annotation(..), mkAnnotation)-import Morley.Tezos.Address.Alias (Alias(..))+import Morley.Tezos.Address.Alias import Morley.Tezos.Core (Mutez(..), mkMutez, unsafeAddMutez, unsafeMulMutez, unsafeSubMutez)+import Morley.Util.TypeLits (symbolValT') instance IsString (Annotation tag) where fromString = unsafe . mkAnnotation . toText@@ -145,5 +148,17 @@ instance (Buildable a, Buildable b) => Buildable (Either a b) where build = eitherF -instance IsString Alias where- fromString = Alias . fromString+instance mname ~ 'Nothing => Default (EntrypointRef mname) where+ def = CallDefault++instance Default U.EpName where+ def = U.DefEpName++instance NiceEntrypointName sym => IsLabel sym U.EpName where+ fromLabel = unsafe . U.buildEpName $ symbolValT' @sym++instance IsString ImplicitAlias where+ fromString = ImplicitAlias . fromString++instance IsString ContractAlias where+ fromString = ContractAlias . fromString
src/Test/Cleveland/Internal/Abstract.hs view
@@ -35,8 +35,13 @@ , Sender (..) , Moneybag (..) , UntypedOriginateData (..)- , RunCode(..)+ , TypedOriginateData (..)+ , LargeOrigination (..)+ , TypedContract (..)+ , RunCode (..) , ClevelandInput+ , ClevelandResult+ , ContractEvent (..) , DefaultAliasCounter (..) , SpecificOrDefaultAlias (..)@@ -58,6 +63,7 @@ , runSingleOperation -- * Validation+ , AddressAndAlias(..) , TransferFailure (..) , TransferFailureReason (..) , FailedInBranch (..)@@ -72,21 +78,30 @@ -- * Morley client re-exports , Alias+ , ImplicitAlias+ , ContractAlias+ , KindedAddress+ , ContractAddress+ , ImplicitAddress -- * Capability records , ClevelandCaps(..) , EmulatedCaps(..)+ , NetworkCaps(..) , HasClevelandCaps(..) , senderL , moneybagL , getMiscCap , getOpsCap , HasEmulatedCaps(..)+ , HasNetworkCaps(..) , MonadCleveland , MonadEmulated+ , MonadNetwork , ClevelandT , EmulatedT+ , NetworkT -- * Log utilities , LogsInfo@@ -97,9 +112,16 @@ , filterLogsByAddrL , logsForAddress , collectLogs++ -- * Network environment+ , NetworkEnv(..)+ , neMorleyClientEnvL+ , neSecretKeyL+ , neMoneybagAliasL+ , neExplicitDataDirL ) where -import Control.Lens (Each, each, filtered, makeLenses, makeLensesFor)+import Control.Lens (Each, each, filtered, makeLenses, makeLensesFor, makeLensesWith) import Data.Default (Default(..)) import Data.Type.Equality (pattern Refl) import Data.Typeable (cast)@@ -109,8 +131,9 @@ import Lorentz (Contract(..)) import Lorentz.Constraints-import Morley.AsRPC (HasRPCRepr(AsRPC), MaybeRPC)-import Morley.Client (Result)+import Lorentz.Entrypoints.Core (EntrypointRef(..), NiceEntrypointName, eprName)+import Morley.AsRPC (HasRPCRepr(AsRPC))+import Morley.Client (MorleyClientEnv, Result) import Morley.Client.Types import Morley.Micheline (Expression, fromExpression) import Morley.Michelson.ErrorPos (ErrorSrcPos)@@ -123,19 +146,25 @@ import Morley.Michelson.Typed.Scope (ConstantScope) import Morley.Michelson.Untyped qualified as U import Morley.Tezos.Address-import Morley.Tezos.Address.Alias (Alias(..))+import Morley.Tezos.Address.Alias import Morley.Tezos.Core (ChainId, Mutez, Timestamp) import Morley.Tezos.Crypto import Morley.Tezos.Crypto qualified as Crypto import Morley.Util.Batching+import Morley.Util.Lens (postfixLFields) import Morley.Util.Sing (eqI) import Morley.Util.TypeLits import Test.Cleveland.Internal.Exceptions (WithCallStack(..)) import Test.Cleveland.Lorentz.Types -data OriginateData param st vd =+-- | Whether this contract should be originated in+-- a single origination operation or, if it goes over+-- the origination size limit, in multiple operations.+data LargeOrigination = IsLarge | NotLarge++data OriginateData param st vd (large :: LargeOrigination) = OriginateData- { odName :: Alias+ { odName :: ContractAlias -- ^ Alias for the originated contract. , odBalance :: Mutez -- ^ Initial balance.@@ -151,8 +180,8 @@ -- | Untyped version of OriginateData. It can be used for interaction with raw -- Michelson contracts-data UntypedOriginateData = UntypedOriginateData- { uodName :: Alias+data UntypedOriginateData (large :: LargeOrigination) = UntypedOriginateData+ { uodName :: ContractAlias -- ^ Alias for the originated contract. , uodBalance :: Mutez -- ^ Initial balance.@@ -162,9 +191,22 @@ -- ^ The contract itself. } +-- | Untyped version of OriginateData. It can be used for interaction with raw+-- Michelson contracts+data TypedOriginateData cp st vd (large :: LargeOrigination) = TypedOriginateData+ { todName :: ContractAlias+ -- ^ Alias for the originated contract.+ , todBalance :: Mutez+ -- ^ Initial balance.+ , todStorage :: st+ -- ^ Initial storage.+ , todContract :: T.Contract (T.ToT cp) (T.ToT st)+ -- ^ The contract itself.+ }+ -- | Information about transfer operation. data TransferData =- forall v addr. (NiceParameter v, ToAddress addr) => TransferData+ forall v addr. (NiceParameter v, ToL1Address addr) => TransferData { tdTo :: addr -- ^ Receiver address for this transaction. , tdAmount :: Mutez@@ -177,13 +219,31 @@ -- for transfers to key addresses. } +-- | A wrapper around t'T.Contract' to reduce awkwardness+data TypedContract cp st vd where+ TypedContract :: T.Contract (T.ToT cp) (T.ToT st) -> TypedContract cp st vd+ -- | Designates an operation input. data ClevelandInput instance OperationInfoDescriptor ClevelandInput where type TransferInfo ClevelandInput = TransferData- type OriginationInfo ClevelandInput = UntypedOriginateData+ type OriginationInfo ClevelandInput = UntypedOriginateData 'NotLarge type RevealInfo ClevelandInput = PublicKey +-- | Data structure representing a contract event.+data ContractEvent = ContractEvent+ { ceSource :: ContractAddress+ , ceTag :: Text+ , cePayload :: Maybe SomeAnnotatedValue+ }++-- | Designates an operation result.+data ClevelandResult+instance OperationInfoDescriptor ClevelandResult where+ type TransferInfo ClevelandResult = [ContractEvent]+ type OriginationInfo ClevelandResult = OriginationInfo Result+ type RevealInfo ClevelandResult = RevealInfo Result+ -- | A batch returned invalid output, e.g. origination address when transaction -- was supplied. data BatchResultMismatch@@ -200,7 +260,7 @@ -- This is initialized to @moneybag@ address and then can be locally modified. -- -- Operations in `ClevelandOpsImpl` are affected by this address.-newtype Sender = Sender { unSender :: Address }+newtype Sender = Sender { unSender :: ImplicitAddress } -- | Designates the address that gifts money to new addresses. --@@ -212,24 +272,24 @@ -- moneybag is not necessary. If a user wraps a large piece of their script with -- 'Test.Cleveland.withSender' call and that changes the moneybag - this behaviour may be -- undesired and unexpected to the user.-newtype Moneybag = Moneybag { unMoneybag :: Address }+newtype Moneybag = Moneybag { unMoneybag :: ImplicitAddress } -- | An alias with default value that can be used to define unique alias -- automatically. data SpecificOrDefaultAlias- = SpecificAlias Alias+ = SpecificAlias ImplicitAlias | DefaultAlias deriving stock (Show) instance IsString SpecificOrDefaultAlias where- fromString = SpecificAlias . Alias . fromString+ fromString = SpecificAlias . ImplicitAlias . fromString instance Default SpecificOrDefaultAlias where def = DefaultAlias -mkDefaultAlias :: Natural -> Alias+mkDefaultAlias :: Natural -> ImplicitAlias mkDefaultAlias counter =- Alias . fromString $ ("default_cleveland_alias" <> show counter)+ ImplicitAlias . fromString $ ("default_cleveland_alias" <> show counter) -- | Helper to use automatically determined unique alias. auto :: SpecificOrDefaultAlias@@ -242,7 +302,7 @@ -- | A record data type with operations creating primitives. data ClevelandOpsImpl m = ClevelandOpsImpl { coiRunOperationBatch- :: HasCallStack => [OperationInfo ClevelandInput] -> m [OperationInfo Result]+ :: HasCallStack => [OperationInfo ClevelandInput] -> m [OperationInfo ClevelandResult] -- ^ Perform a batch of operations. } @@ -250,19 +310,19 @@ data ClevelandMiscImpl m = ClevelandMiscImpl { cmiRunIO :: forall res. HasCallStack => IO res -> m res -- ^ Runs an 'IO' action.- , cmiResolveAddress :: HasCallStack => Alias -> m Address+ , cmiResolveAddress :: forall kind. HasCallStack => Alias kind -> m (KindedAddress kind) -- ^ Get the address of the implicit account / contract associated with the given alias.- , cmiGenKey :: HasCallStack => SpecificOrDefaultAlias -> m Address+ , cmiGenKey :: HasCallStack => SpecificOrDefaultAlias -> m ImplicitAddress -- ^ Generate a secret key and store it with given alias. -- If a key with this alias already exists, the corresponding address -- will be returned and no state will be changed.- , cmiGenFreshKey :: HasCallStack => SpecificOrDefaultAlias -> m Address+ , cmiGenFreshKey :: HasCallStack => SpecificOrDefaultAlias -> m ImplicitAddress -- ^ Generate a secret key and store it with given alias. -- Unlike 'cmiGenKey' this function overwrites the existing key when -- given alias is already stored.- , cmiSignBytes :: HasCallStack => ByteString -> Address -> m Crypto.Signature+ , cmiSignBytes :: HasCallStack => ByteString -> ImplicitAddress -> m Crypto.Signature -- ^ Get the signature of the preapplied operation.- , cmiOriginateLargeUntyped :: HasCallStack => Sender -> UntypedOriginateData -> m Address+ , cmiOriginateLargeUntyped :: HasCallStack => Sender -> UntypedOriginateData 'IsLarge -> m ContractAddress -- ^ Originate a new raw Michelson contract that doesn't fit into the -- origination size limit, by executing multiple operation steps. --@@ -272,9 +332,9 @@ , cmiComment :: HasCallStack => Text -> m () -- ^ Print the given string verbatim as a comment. -- At the moment, this is a no-op in emulator tests.- , cmiGetBalance :: HasCallStack => Address -> m Mutez+ , cmiGetBalance :: HasCallStack => L1Address -> m Mutez -- ^ Get the balance of the given address.- , cmiGetSomeStorage :: HasCallStack => Address -> m SomeAnnotatedValue+ , cmiGetSomeStorage :: HasCallStack => ContractAddress -> m SomeAnnotatedValue -- Retrieves the contract's storage. , cmiGetBigMapValueMaybe :: forall k v. (HasCallStack, NiceComparable k, NicePackedValue k, NiceUnpackedValue v)@@ -287,12 +347,12 @@ => BigMapId k v -> m (Maybe [v]) -- ^ Retrieve all big_map values, given a big_map ID. -- Returns 'Nothing' when the big_map ID does not exist.- , cmiGetPublicKey :: HasCallStack => Address -> m Crypto.PublicKey+ , cmiGetPublicKey :: HasCallStack => ImplicitAddress -> m Crypto.PublicKey -- ^ Get the public key associated with the given address. -- Fail if the given address is not an implicit account.- , cmiGetDelegate :: HasCallStack => Address -> m (Maybe Crypto.KeyHash)+ , cmiGetDelegate :: HasCallStack => ContractAddress -> m (Maybe Crypto.KeyHash) -- ^ Get the delegate for the given contract. Fails on implicit contracts.- , cmiRegisterDelegate :: HasCallStack => Address -> m ()+ , cmiRegisterDelegate :: HasCallStack => ImplicitAddress -> m () -- ^ Register the given address as a valid delegate. , cmiGetChainId :: HasCallStack => m ChainId -- ^ Get the chain's @ChainId@.@@ -318,11 +378,12 @@ -- is minimal bound and real intervals can be larger. , cmiAttempt :: forall a e. (Exception e, HasCallStack) => m a -> m (Either e a) -- ^ Attempts to perform an action, returning either the result of the action or an exception.- , cmiMarkAddressRefillable :: Address -> m ()+ , cmiMarkAddressRefillable :: ImplicitAddress -> m () -- ^ Marks a given address as "refillable", i.e. if the address lacks funds for the next operation, -- some funds will automatically be transferred to it.- , cmiEmulatedImpl :: m (Maybe (EmulatedImpl m))- -- ^ Produce 'EmulatedImpl' if possible. Used to run emulated actions in polymorphic context.+ , cmiUnderlyingImpl :: m (Either (EmulatedImpl m) NetworkEnv)+ -- ^ Produce underlying implementation specific data. Used to run+ -- emulation-only or network-only actions in a polymorphic context. , cmiRunCode :: forall cp st vd. (HasCallStack, HasRPCRepr st, T.IsoValue (AsRPC st)) => Sender -> RunCode cp st vd -> m (AsRPC st)@@ -333,8 +394,20 @@ -- | The data needed to call the @/run_code@ RPC endpoint. data RunCode cp st vd = RunCode { rcContract :: Contract cp st vd- , rcStorage :: MaybeRPC st- , rcParameter :: MaybeRPC cp+ , rcParameter :: U.Value+ -- ^ The parameter value should have the same "structure" as @cp@, except it _may_ also have big_map IDs.+ -- E.g. if the contract's parameter is @pair (big_map string string) (big_map string string)@,+ -- then 'rcParameter' may be one of:+ --+ -- * @pair (big_map string string) (big_map string string)@+ -- * @pair nat (big_map string string)@+ -- * @pair (big_map string string) nat@+ -- * @pair nat nat@+ --+ -- ... where @nat@ represents a big_map ID.+ , rcStorage :: U.Value+ -- ^ The storage value should have the same "structure" as @st@, except it _may_ also have big_map IDs.+ -- See the documentation of 'rcParameter'. , rcAmount :: Mutez -- ^ The value that will be returned by the @AMOUNT@ instruction. , rcLevel :: Maybe Natural@@ -343,7 +416,7 @@ -- ^ The value that will be returned by the @NOW@ instruction. , rcBalance :: Mutez -- ^ The balance that will be returned by the @BALANCE@ instruction.- , rcSource :: Maybe Address+ , rcSource :: Maybe ImplicitAddress -- ^ The value that will be returned by the @SOURCE@ instruction. } @@ -376,6 +449,13 @@ -- ^ Change voting power distribution. } +data NetworkEnv = NetworkEnv+ { neMorleyClientEnv :: MorleyClientEnv+ , neSecretKey :: Maybe Crypto.SecretKey+ , neMoneybagAlias :: ImplicitAlias+ , neExplicitDataDir :: Bool+ }+ ---------------------------------------------------------------------------- -- Log helpers ----------------------------------------------------------------------------@@ -388,6 +468,7 @@ type LogsInfo = [ScenarioLogs] makeLenses ''ScenarioLogs+makeLensesWith postfixLFields ''NetworkEnv -- | An alias for 'slLog' with a clearer name logsL :: Lens' ScenarioLogs MorleyLogs@@ -426,7 +507,7 @@ -- @-XApplicativeDo@ extension for nicer experience. newtype ClevelandOpsBatch a = ClevelandOpsBatch { unClevelandOpsBatch- :: BatchingM (OperationInfo ClevelandInput) (OperationInfo Result) Void a+ :: BatchingM (OperationInfo ClevelandInput) (OperationInfo ClevelandResult) Void a } deriving newtype (Functor, Applicative) instance@@ -480,7 +561,7 @@ :: (HasCallStack, Buildable e, Functor m) => Proxy e -> ClevelandOpsImpl m- -> BatchingM (OperationInfo ClevelandInput) (OperationInfo Result) e a+ -> BatchingM (OperationInfo ClevelandInput) (OperationInfo ClevelandResult) e a -> m a runOperationBatchM _ impl = fmap snd . unsafeRunBatching (fmap ((), ) . coiRunOperationBatch impl)@@ -491,7 +572,7 @@ => ClevelandOpsImpl m -> Text -> OperationInfo ClevelandInput- -> (OperationInfo Result -> Maybe a)+ -> (OperationInfo ClevelandResult -> Maybe a) -> m a runSingleOperation impl desc opData parseRes = runOperationBatchM (Proxy @BatchResultMismatch) impl $@@ -521,10 +602,17 @@ EOTVExpression e -> either (const $ build e) build $ fromExpression @U.Value e EOTVTypedValue v -> build v +data AddressAndAlias = AddressAndAlias Address (Maybe ContractAlias)+ deriving stock (Show, Eq)++instance Buildable AddressAndAlias where+ build (AddressAndAlias addr mbAlias) =+ build addr +| maybe "" (\alias -> " (" +| alias |+ ")") mbAlias+ -- | Failures that could be expected in the execution of a transfer. -- These can be caught and handled with 'Test.Cleveland.attempt'. data TransferFailure = TransferFailure- { tfAddress :: Address+ { tfAddressAndAlias :: AddressAndAlias , tfReason :: TransferFailureReason } deriving stock (Show, Eq) @@ -542,7 +630,7 @@ -- ^ Expect that interpretation of contract with the given address ended -- with an overflow error. | GasExhaustion- -- TODO: [#284] add more errors here!+ -- TODO [#284]: add more errors here! deriving stock (Show, Eq) -- | When an exception is thrown in a 'Test.Cleveland.branchout' branch, we wrap it in this@@ -614,16 +702,39 @@ -- Other helpers ---------------------------------------------------------------------------- --- | A short partial constructor for 'EpName'. It is supposed to be--- applied to string constants, so programmer is responsible for--- validity. And this code is for tests anyway, so each failure is a--- programmer mistake.------ It is intentionally here and not in some deeper module because the--- name is really short and more suitable for writing scenarios.-ep :: HasCallStack => Text -> EpName-ep = unsafe . U.buildEpName+class NiceEntrypointName epName => EntrypointNameConstructor (epName :: Symbol) a where+ -- | A short partial constructor for 'EpName' or 'EntrypointRef'. It accepts a+ -- type-level string as its type argument. The programmer is responsible for+ -- validity. And this code is for tests anyway, so each failure is a+ -- programmer mistake.+ --+ -- Note that entrypoint names should be capitalized, e.g.+ --+ -- > ep @"Entrypoint"+ --+ -- corresponds to @entrypoint@, etc.+ --+ -- It is intentionally here and not in some deeper module because the name is+ -- really short and more suitable for writing scenarios.+ --+ -- For 'EpName', an instance is provided accepting a value-level t'Text'+ -- instead of a type-level symbol. This is mostly for cases where the+ -- type-level symbol doesn't work. Note that value-level string will be used+ -- verbatim, hence capitalization is arbitrary.+ --+ -- > ep "entrypoint"+ ep :: a +instance (NiceEntrypointName epName, mname ~ 'Just epName)+ => EntrypointNameConstructor epName (EntrypointRef mname) where+ ep = Call++instance NiceEntrypointName epName => EntrypointNameConstructor epName EpName where+ ep = eprName $ Call @epName++instance (any ~ "", t ~ Text) => EntrypointNameConstructor any (t -> EpName) where+ ep = unsafe . U.buildEpName+ -- | Runs a handler over every action. mapClevelandOpsImplExceptions :: (forall a. HasCallStack => m a -> m a)@@ -662,7 +773,7 @@ , cmiAttempt = \action -> cmiAttempt action , cmiMarkAddressRefillable = f . cmiMarkAddressRefillable , cmiThrow = cmiThrow- , cmiEmulatedImpl = f $ cmiEmulatedImpl+ , cmiUnderlyingImpl = f $ cmiUnderlyingImpl , cmiRunCode = f ... cmiRunCode } @@ -680,8 +791,15 @@ , ecClevelandCaps :: ClevelandCaps m } +-- | A record with all the capabilities available to a cleveland test on the network.+data NetworkCaps m = NetworkCaps+ { ncNetworkEnv :: NetworkEnv+ , ncClevelandCaps :: ClevelandCaps m+ }+ makeLensesFor [("ccSender", "ccSenderL"), ("ccMoneybag", "ccMoneybagL")] ''ClevelandCaps makeLensesFor [("ecClevelandCaps", "ecClevelandCapsL")] ''EmulatedCaps+makeLensesFor [("ncClevelandCaps", "ncClevelandCapsL")] ''NetworkCaps -- | A proof that the given @caps@ record contains -- the basic cleveland capabilities.@@ -691,7 +809,7 @@ clevelandCapsL :: Lens' caps (ClevelandCaps (ClevelandBaseMonad caps)) -- | A proof that the given @caps@ record contains--- the basic cleveland capabilities + the emulator capabiilities.+-- the basic cleveland capabilities + the emulator capabilities. class HasClevelandCaps caps => HasEmulatedCaps caps where getEmulatedCap :: caps -> EmulatedImpl (ClevelandBaseMonad caps) @@ -718,21 +836,43 @@ instance Monad m => HasEmulatedCaps (EmulatedCaps m) where getEmulatedCap = ecEmulatedCap +-- | A proof that the given @caps@ record contains+-- the basic cleveland capabilities + the network capabilities.+class HasClevelandCaps caps => HasNetworkCaps caps where+ getNetworkEnvCap :: caps -> NetworkEnv++instance Monad m => HasClevelandCaps (NetworkCaps m) where+ type ClevelandBaseMonad (NetworkCaps m) = m+ clevelandCapsL = ncClevelandCapsL++instance Monad m => HasNetworkCaps (NetworkCaps m) where+ getNetworkEnvCap = ncNetworkEnv+ -- | Constraint for a monad in which we can do cleveland actions. type MonadCleveland caps m = ( m ~ ReaderT caps (ClevelandBaseMonad caps) , HasClevelandCaps caps ) --- | Constraint for a monad in which we can do cleveland actions that can't be run on a real network.--- It requires the 'EmulatedImpl' capability.+-- | Constraint for a monad in which we can do cleveland actions that can't be+-- run on a real network. It requires the 'EmulatedCaps' capability. type MonadEmulated caps m = ( MonadCleveland caps m , HasEmulatedCaps caps ) +-- | Constraint for a monad in which we can do cleveland actions that can only+-- be run on a real network. It requires the 'NetworkCaps' capability.+type MonadNetwork caps m =+ ( MonadCleveland caps m+ , HasNetworkCaps caps+ )+ -- | Monad transformer that adds only the 'ClevelandCaps' capabilities. type ClevelandT m = ReaderT (ClevelandCaps m) m -- | Monad transformer that adds both 'ClevelandCaps' and 'EmulatedCaps' capabilities. type EmulatedT m = ReaderT (EmulatedCaps m) m++-- | Monad transformer that adds both 'ClevelandCaps' and 'NetworkCaps' capabilities.+type NetworkT m = ReaderT (NetworkCaps m) m
src/Test/Cleveland/Internal/Actions.hs view
@@ -3,1254 +3,123 @@ -- | Cleveland actions. module Test.Cleveland.Internal.Actions- ( MonadOps(..)- , withSender- , withMoneybag- , runIO- , resolveAddress- , refillable- , newAddress- , newAddresses- , newFreshAddress- , enumAliases- , signBytes- , signBinary- , originate- , originateSimple- , originateUntyped- , originateUntypedSimple- , originateTypedSimple- , originateLarge- , originateLargeSimple- , originateLargeUntyped- , originateLargeUntypedSimple- , transfer- , transferMoney- , call- , inBatch- , importUntypedContract- , importContract- , noViews- , comment- , getBalance- , getStorage- , getFullStorage- , getSomeStorage- , getAllBigMapValues- , getAllBigMapValuesMaybe- , getBigMapSize- , getBigMapSizeMaybe- , getBigMapValueMaybe- , getBigMapValue- , getMorleyLogs- , getMorleyLogs_- , getPublicKey- , getChainId- , advanceTime- , advanceLevel- , advanceToLevel- , getNow- , getLevel- , getApproximateBlockInterval- , getMinBlockTime- , runCode- , branchout- , offshoot- , getDelegate- , registerDelegate- , setVotingPowers- , whenEmulation- , whenNetwork- , ifEmulation-- -- * Assertions- , failure- , assert- , (@==)- , (@/=)- , (@@==)- , (@@/=)- , checkCompares- , checkComparesWith- , evalJust- , evalRight-- -- * Exception handling- , attempt- , catchTransferFailure- , checkTransferFailure- , expectTransferFailure- , expectFailedWith- , expectError- , expectCustomError- , expectCustomError_- , expectCustomErrorNoArg- , expectNumericError- , clarifyErrors- -- ** TransferFailure predicates- , TransferFailurePredicate(..)- , shiftOverflow- , emptyTransaction- , badParameter- , gasExhaustion- , failedWith- , addressIs- -- ** @FAILWITH@ errors- , constant- , lerror- , customError- , customError_- , customErrorNoArg- , numericError-- -- * Helpers- , withCap- ) where--import Data.Constraint (Dict(Dict), (\\))-import Data.Either.Validation (Validation(..))-import Data.List.NonEmpty qualified as NE-import Data.Singletons (demote)-import Fmt (Buildable, Builder, build, indentF, nameF, pretty, unlinesF, (+|), (|+))-import Time (KnownDivRat, Second, Time, toNum)-import Unsafe qualified (fromIntegral)--import Lorentz- (BigMapId, Contract(..), CustomError(..), DemoteViewsDescriptor, ErrorTagMap,- HasEntrypointArg(useHasEntrypointArg), IsError, IsoValue, Label, MText, MustHaveErrorArg,- ToTAddress, errorTagToMText, errorToVal, errorToValNumeric, noViews, pattern DefEpName,- toMichelsonContract, toTAddress, toVal, zeroMutez)-import Lorentz.Bytes-import Lorentz.Constraints-import Morley.AsRPC (HasRPCRepr(..))-import Morley.Client (OperationInfo(..))-import Morley.Micheline (Expression, fromExpression, toExpression)-import Morley.Michelson.Printer.Util (buildRenderDoc)-import Morley.Michelson.Runtime (VotingPowers)-import Morley.Michelson.Runtime.Import qualified as Runtime-import Morley.Michelson.Typed- (SomeAnnotatedValue, SomeConstant, SomeConstrainedValue(..), convertContract, untypeValue)-import Morley.Michelson.Typed qualified as T-import Morley.Michelson.Typed.AnnotatedValue (castTo, getT, value)-import Morley.Michelson.Untyped qualified as U-import Morley.Tezos.Address (Address)-import Morley.Tezos.Address.Alias (Alias(..))-import Morley.Tezos.Core (ChainId, Mutez, Timestamp)-import Morley.Tezos.Crypto (KeyHash, PublicKey, Signature)-import Morley.Util.SizedList qualified as SL-import Morley.Util.SizedList.Types-import Test.Cleveland.Internal.Abstract-import Test.Cleveland.Internal.Client qualified as Client (TestError(..))-import Test.Cleveland.Internal.Exceptions (WithCallStack(..))-import Test.Cleveland.Internal.Pure as Pure (TestError(..))-import Test.Cleveland.Lorentz.Import qualified as LorentzImport-import Test.Cleveland.Lorentz.Types--{-# ANN module ("HLint: ignore Avoid lambda using `infix`" :: Text) #-}---- $setup--- >>> :m +Morley.Util.SizedList.Types--- >>> :{--- isEquivalentTo :: Show a => a -> a -> Bool--- isEquivalentTo a b = show a == show b--- infix 0 `isEquivalentTo`--- :}---- | Typeclass for monads where operations-related actions can occur.------ This is implemented for 'MonadCleveland' and batch context.------ Has 'Functor' as a superclass constraint for convenience, all the related methods--- require it.-class Functor m => MonadOps m where- -- | Obtain 'ClevelandOpsImpl' suitable for the current \"monad\".- --- -- In CPS style, because the \"monad\" can be actually not a monad, so- -- it can't work like 'ask' for 'ReaderT'.- withOpsCap :: (ClevelandOpsImpl m -> m a) -> m a--instance MonadOps ClevelandOpsBatch where- withOpsCap mkAction = mkAction batchedOpsImpl--instance (HasClevelandCaps caps, ClevelandBaseMonad caps ~ m) => MonadOps (ReaderT caps m) where- withOpsCap mkAction = do- opsCap :: ClevelandOpsImpl m <- asks getOpsCap- let opsCap' :: ClevelandOpsImpl (ReaderT caps m) =- ClevelandOpsImpl- { coiRunOperationBatch = lift ... coiRunOperationBatch opsCap- }- mkAction opsCap'---- | Update the current sender on whose behalf transfers and originations are--- invoked.-withSender :: MonadCleveland caps m => Address -> m a -> m a-withSender addr =- local (set senderL (Sender addr))---- | Update the current moneybag that transfers money on the newly created--- addresses. For the rare occasions when this is necessary.-withMoneybag :: MonadCleveland caps m => Address -> m a -> m a-withMoneybag addr =- local (set moneybagL (Moneybag addr))---- | Runs an 'IO' action.-runIO :: (HasCallStack, MonadCleveland caps m) => IO res -> m res-runIO io = do- withCap getMiscCap \cap -> cmiRunIO cap io---- | Get the address of the implicit account / contract associated with the given alias.-resolveAddress- :: (HasCallStack, MonadCleveland caps m)- => Alias -> m Address-resolveAddress alias = do- withCap getMiscCap \cap -> cmiResolveAddress cap alias---- | Simple combinator that marks address as "refillable".------ If a refillable address lacks funds for the next operation,--- some funds will automatically be transferred to it.-refillable :: MonadCleveland caps m => m Address -> m Address-refillable action = do- addr <- action- withCap getMiscCap \cap -> cmiMarkAddressRefillable cap addr- pure addr---- | If the given alias is already associated with an existing address,--- that address will be reused and returned.--- Otherwise, generate a new secret key and record it with given alias.------ If the account has too low of a balance, a small amount of XTZ will--- be transferred to it.------ Notes:------ * By default, the XTZ is transferred from the account associated with the @moneybag@ alias.--- This can be overriden with the @--cleveland-moneybag-alias@ command line option, the--- @TASTY_CLEVELAND_MONEYBAG_ALIAS@ env var, or 'withMoneybag'.--- > do--- > addr1 <- newAddress "alias"--- > addr2 <- resolveAddress $ mkAlias "prefix.alias"--- > addr1 @== addr2-newAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m Address-newAddress alias = do- addrs <- newAddresses $ alias :< Nil- case addrs of- addr :< Nil -> pure addr---- | Batched version of `newAddress`-newAddresses- :: forall n n' caps m.- (HasCallStack, MonadCleveland caps m, IsoNatPeano n n')- => SizedList n SpecificOrDefaultAlias- -> m (SizedList n Address)-newAddresses aliases = do- addrs <- withCap getMiscCap \cap -> traverse (cmiGenKey cap) aliases- Moneybag moneybag <- view moneybagL-- -- Addresses may exist from previous scenarios runs and have sufficient- -- balance for the sake of testing; if so, we can save some time- balances <- traverse getBalance addrs- withSender moneybag do- inBatch do- sequenceA_ $- SL.zipWith refillIfLowBalance addrs balances-- pure addrs--refillIfLowBalance :: (HasCallStack, Applicative m, MonadOps m) => Address -> Mutez -> m ()-refillIfLowBalance addr balance =- when (balance < 0.5_e6) do -- < 0.5 XTZ- transferMoney addr 0.9_e6 -- 0.9 XTZ---- | Generate a new secret key and record it with given alias. If the--- alias is already known, the key will be overwritten. The address is--- guaranteed to be fresh, i. e. no operations on it have been made.------ Notes:------ * Beware that if an "alias prefix" is set, it'll be prepended to the given alias.--- An "alias prefix" can be set using the @--cleveland-alias-prefix@ command line option, the--- @TASTY_CLEVELAND_ALIAS_PREFIX@ env var, or with 'Test.Cleveland.Tasty.setAliasPrefix'.--- > do--- > addr1 <- newFreshAddress "alias"--- > addr2 <- resolveAddress $ mkAlias "prefix.alias"--- > addr1 @== addr2-newFreshAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m Address-newFreshAddress alias = do- withCap getMiscCap \cap -> cmiGenFreshKey cap alias---- | Get the signature of the preapplied operation.-signBytes :: (HasCallStack, MonadCleveland caps m) => ByteString -> Address -> m Signature-signBytes bytes signer = do- withCap getMiscCap \cap -> cmiSignBytes cap bytes signer---- | Create a list of similarly named 'SpecificAlias'es.------ For example,------ >>> enumAliases @2 "operator" `isEquivalentTo` "operator-0" :< "operator-1" :< Nil--- True-enumAliases- :: forall n n'.- (SingIPeano n, IsoNatPeano n n')- => Alias -> SizedList n SpecificOrDefaultAlias-enumAliases (Alias pfx) = SpecificAlias <$> SL.generate @n (\n -> Alias $ pfx <> "-" <> show n)---- | Type-safer version of 'signBytes'.-signBinary :: (HasCallStack, BytesLike bs, MonadCleveland caps m) => bs -> Address -> m (TSignature bs)-signBinary bs addr = TSignature <$> signBytes (toBytes bs) addr---- | Originate a new raw Michelson contract with given data.-originateUntyped :: (HasCallStack, MonadOps m) => UntypedOriginateData -> m Address-originateUntyped uod = withOpsCap \opsCap ->- runSingleOperation opsCap "origination" (OpOriginate uod) \case- OpOriginate addr -> Just addr- _ -> Nothing---- | A simplified version of the originateUntyped command.--- The contract will have 0 balance.-originateUntypedSimple- :: (HasCallStack, MonadOps m) => Alias -> U.Value -> U.Contract -> m Address-originateUntypedSimple uodName uodStorage uodContract = do- let uodBalance = zeroMutez- originateUntyped UntypedOriginateData{..}---- | Lorentz version for origination.------ By default, the sender is the account associated with the @moneybag@ alias.--- This can be overriden with the @--cleveland-moneybag-alias@ command line option, the--- @TASTY_CLEVELAND_MONEYBAG_ALIAS@ env var, or 'withSender'.-originate- :: forall cp st vd m.- (HasCallStack, MonadOps m)- => OriginateData cp st vd -> m (ContractHandle cp st vd)-originate dat@OriginateData{ odContract = Contract{}, .. } = do- addr <- originateUntyped (originateDataToUntyped dat)- pure $ ContractHandle (pretty odName) addr---- | A simplified version of the originate command.--- The contract will have 0 balance.-originateSimple- :: forall cp st vd m.- ( HasCallStack- , MonadOps m- )- => Alias- -> st- -> Contract cp st vd- -> m (ContractHandle cp st vd)-originateSimple odName odStorage odContract = do- let odBalance = zeroMutez- originate OriginateData{..}---- | Like 'originateUntypedSimple', but accepts typed contract and initial storage--- as a Haskell value.-originateTypedSimple- :: forall cp st vd m.- ( HasCallStack- , MonadOps m- , NiceParameter cp, NiceStorage st, NiceViewsDescriptor vd- )- => Alias -> st -> T.Contract (T.ToT cp) (T.ToT st) -> m (ContractHandle cp st vd)-originateTypedSimple name storage contract@T.Contract{} = do- addr <- originateUntypedSimple name (untypeHelper storage) (convertContract contract)- pure $ ContractHandle (pretty name) addr---- | Originate a new Michelson contract that doesn't fit into the--- origination size limit, by executing multiple operation steps.------ This operation cannot be batched (it simply may not fit).-originateLargeUntyped- :: (HasCallStack, MonadCleveland caps m) => UntypedOriginateData -> m Address-originateLargeUntyped uod = do- sender <- view senderL- withCap getMiscCap \cap -> cmiOriginateLargeUntyped cap sender uod---- | A simplified version of the originateLargeUntyped command.--- The contract will have 0 balance.-originateLargeUntypedSimple- :: (HasCallStack, MonadCleveland caps m)- => Alias -> U.Value -> U.Contract -> m Address-originateLargeUntypedSimple uodName uodStorage uodContract = do- let uodBalance = zeroMutez- originateLargeUntyped UntypedOriginateData{..}---- | Lorentz version for large origination.-originateLarge- :: forall param st vd m caps.- (HasCallStack, MonadCleveland caps m)- => OriginateData param st vd -> m (ContractHandle param st vd)-originateLarge dat@OriginateData{ odContract = Contract{}, .. } = do- addr <- originateLargeUntyped (originateDataToUntyped dat)- pure $ ContractHandle (pretty odName) addr---- | A simplified version of the originateLarge command.--- The contract will have 0 balance.-originateLargeSimple- :: forall param st vd m caps.- ( HasCallStack- , MonadCleveland caps m- )- => Alias- -> st- -> Contract param st vd- -> m (ContractHandle param st vd)-originateLargeSimple odName odStorage odContract = do- let odBalance = zeroMutez- originateLarge OriginateData{..}---- | Base method for making a transfer.------ Avoid using this method in favour of 'transferMoney' and 'call', unless--- you need the semantics of both in one operation.-transfer :: (HasCallStack, MonadOps m) => TransferData -> m ()-transfer td = withOpsCap \opsCap ->- runSingleOperation opsCap "transfer" (OpTransfer td) \case- OpTransfer () -> Just ()- _ -> Nothing---- | Simply transfer money to an address.------ This assumes that target address is either an implicit address or has--- a default entrypoint with a unit argument; otherwise the call fails.-transferMoney :: (HasCallStack, MonadOps m, ToAddress addr) => addr -> Mutez -> m ()-transferMoney to amount = transfer TransferData- { tdTo = to- , tdAmount = amount- , tdEntrypoint = DefEpName- , tdParameter = ()- }---- | Call a certain entrypoint of the given contract.------ By default, the sender is the account associated with the @moneybag@ alias.--- This can be overriden with the @--cleveland-moneybag-alias@ command line option, the--- @TASTY_CLEVELAND_MONEYBAG_ALIAS@ env var, or 'withSender'.-call- :: forall param vd addr m epRef epArg.- (HasCallStack, MonadOps m, ToTAddress param vd addr, HasEntrypointArg param epRef epArg- , IsoValue epArg, Typeable epArg)- => addr- -> epRef- -> epArg- -> m ()-call to epRef param =- case useHasEntrypointArg @param @epRef @epArg epRef of- (Dict, epName) ->- transfer TransferData- { tdTo = toAddress $ toTAddress @param @vd @addr to- , tdAmount = zeroMutez- , tdEntrypoint = epName- , tdParameter = param- }---- | Import an untyped contract from file.-importUntypedContract :: (HasCallStack, MonadCleveland caps m) => FilePath -> m U.Contract-importUntypedContract = runIO . Runtime.importUntypedContract---- | Import a contract from file.------ The compiler must be able to infer the types of parameter, storage and views.--- In case there are no views or you don't care, you can use 'noViews'.-importContract- :: ( HasCallStack, NiceParameter param, NiceStorage st- , NiceViewsDescriptor vd, DemoteViewsDescriptor vd- , MonadCleveland caps m- )- => FilePath -> m (Contract param st vd)-importContract = runIO . LorentzImport.importContract--{- | Run operations in a batch.-Best used with the @ApplicativeDo@ GHC extension.--Example:--@-{-# LANGUAGE ApplicativeDo #-}--contract <- inBatch $ do- contract <- originate ...- for_ [1..3] \i ->- transfer ...- return contract-@--Batched operations should be applied to chain faster, but note that batches have-their own limits. For instance, at the moment of writing, the gas limit on a-batch is 10x of gas limit applied to a single operation.--A context of a batch is only 'Applicative', not 'Monad'. This means that:--* Return values of one function cannot be passed to another function in the same- batch, it can only be returned;-* Sometimes the compiler does not recognize that only 'Applicative' context is- required, in case of any issues with that - follow the error messages.---}-inBatch :: (HasCallStack, MonadCleveland caps m) => ClevelandOpsBatch a -> m a-inBatch batch = do- withCap getOpsCap \cap -> runBatched cap batch---- | Print the given string verbatim as a comment.--- At the moment, this is a no-op in emulator tests.-comment :: (HasCallStack, MonadCleveland caps m) => Text -> m ()-comment cmt = do- withCap getMiscCap \cap -> cmiComment cap cmt---- | Get the balance of the given address.-getBalance :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m Mutez-getBalance addr = do- withCap getMiscCap \cap -> cmiGetBalance cap (toAddress addr)---- | Get the delegate for the given contract. Fails on implicit contracts.-getDelegate :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m (Maybe KeyHash)-getDelegate addr = do- withCap getMiscCap \cap -> cmiGetDelegate cap (toAddress addr)---- | Register the given address as a valid delegate.-registerDelegate :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m ()-registerDelegate addr = do- withCap getMiscCap \cap -> cmiRegisterDelegate cap (toAddress addr)---- | Retrieve a contract's storage in its "RPC representation"--- (i.e., all its big_maps will be replaced by big_map IDs).------ If the storage is of a user-defined type, then 'Test.Cleveland.deriveRPC' /--- 'Test.Cleveland.deriveManyRPC' should be used to create an RPC representation of the storage--- type.------ > data MyStorage = MyStorage { field1 :: Natural, field2 :: BigMap Integer MText }--- > deriveRPC "MyStorage"-getStorage- :: forall st addr caps m.- (HasCallStack, MonadCleveland caps m, ToStorageType st addr, IsoValue (AsRPC st))- => addr- -> m (AsRPC st)-getStorage contract = do- someSt <- getSomeStorage contract- case someSt ^? castTo @(AsRPC st) . value of- Just st -> pure st- Nothing -> failure $ unlinesF- [ "Expected storage to be of type:"- , indentF 2 $ build $ demote @(T.ToT (AsRPC st))- , "But its type was:"- , indentF 2 $ build $ getT someSt- ]---- | Retrieve a contract's full storage, including the contents of its big_maps.------ This function can only be used in emulator-only tests.-getFullStorage- :: forall st addr caps m.- (HasCallStack, MonadEmulated caps m, ToStorageType st addr)- => addr- -> m st-getFullStorage contract = do- withCap getEmulatedCap \cap -> eiGetStorage cap contract---- | Similar to 'getStorage', but doesn't require knowing--- the storage type in advance.------ Use the optics in 'Morley.Michelson.Typed.AnnotatedValue' to--- read data from the storage.-getSomeStorage- :: forall addr caps m.- (HasCallStack, MonadCleveland caps m, ToAddress addr)- => addr- -> m SomeAnnotatedValue-getSomeStorage contract = do- withCap getMiscCap \cap -> cmiGetSomeStorage cap (toAddress contract)---- | Retrieve a big_map value, given a big_map ID and a key.--- Returns 'Nothing' when the big_map ID does not exist, or it exists but--- does not contain the given key.-getBigMapValueMaybe- :: forall k v caps m.- ( HasCallStack, MonadCleveland caps m- , NiceComparable k, NicePackedValue k, NiceUnpackedValue v- )- => BigMapId k v -> k -> m (Maybe v)-getBigMapValueMaybe bmId key = do- withCap getMiscCap \cap -> cmiGetBigMapValueMaybe cap bmId key---- | Like 'getBigMapValueMaybe', but fails the tests instead of returning 'Nothing'.-getBigMapValue- :: forall k v caps m.- ( HasCallStack, MonadCleveland caps m- , NiceComparable k, NicePackedValue k, NiceUnpackedValue v- , Buildable k- )- => BigMapId k v -> k -> m v-getBigMapValue bmId k =- getBigMapValueMaybe bmId k >>= \case- Just v -> pure v- Nothing -> failure $ unlinesF @_ @Builder- [ "Either:"- , " 1. A big_map with ID '" +| bmId |+ "' does not exist, or"- , " 2. It exists, but does not contain the key '" +| k |+ "'."- ]---- | Retrieve all big_map values, given a big_map ID.--- Returns 'Nothing' when the big_map ID does not exist.-getAllBigMapValuesMaybe- :: forall k v caps m.- ( HasCallStack, MonadCleveland caps m- , NiceComparable k, NiceUnpackedValue v- )- => BigMapId k v -> m (Maybe [v])-getAllBigMapValuesMaybe bmId = do- withCap getMiscCap \cap -> cmiGetAllBigMapValuesMaybe cap bmId---- | Like 'getAllBigMapValuesMaybe', but fails the tests instead of returning 'Nothing'.-getAllBigMapValues- :: forall k v caps m.- ( HasCallStack, MonadCleveland caps m- , NiceComparable k, NiceUnpackedValue v- )- => BigMapId k v -> m [v]-getAllBigMapValues bmId =- getAllBigMapValuesMaybe bmId >>= \case- Just vs -> pure vs- Nothing -> failure $ "A big map with ID '" +| bmId |+ "' does not exist"---- | Retrieve a big_map size, given a big_map ID.--- Returns 'Nothing' when the big_map ID does not exist.------ /O(n)/, because it's implemented with 'Morley.Client.RPC.Getters.getBigMapValues'.-getBigMapSizeMaybe- :: forall k v caps m.- ( HasCallStack, MonadCleveland caps m- , NiceComparable k, NiceUnpackedValue v- )- => BigMapId k v -> m (Maybe Natural)-getBigMapSizeMaybe bmId =- fmap (fmap (Unsafe.fromIntegral @Int @Natural . length)) (getAllBigMapValuesMaybe bmId)---- | Like 'getBigMapSizeMaybe', but fails the tests instead of returning 'Nothing'.-getBigMapSize- :: forall k v caps m.- ( HasCallStack, MonadCleveland caps m- , NiceComparable k, NiceUnpackedValue v- )- => BigMapId k v -> m Natural-getBigMapSize bmId =- Unsafe.fromIntegral @Int @Natural . length <$> getAllBigMapValues bmId---- | Get the public key associated with given address.--- Fail if given address is not an implicit account.-getPublicKey :: (HasCallStack, MonadCleveland caps m) => Address -> m PublicKey-getPublicKey addr = do- withCap getMiscCap \cap -> cmiGetPublicKey cap addr---- | Get the chain's @ChainId@.-getChainId :: (HasCallStack, MonadCleveland caps m) => m ChainId-getChainId = do- withCap getMiscCap \cap -> cmiGetChainId cap---- | Advance at least the given amount of time, or until a new block is baked,--- whichever happens last.------ On a real network, this is implemented using @threadDelay@, so it's advisable--- to use small amounts of time only.-advanceTime- :: forall unit caps m- . (HasCallStack, MonadCleveland caps m, KnownDivRat unit Second)- => Time unit -> m ()-advanceTime time = do- withCap getMiscCap \cap -> cmiAdvanceTime cap time---- | Wait till the provided number of levels is past.-advanceLevel- :: forall caps m- . (HasCallStack, MonadCleveland caps m)- => Natural -> m ()-advanceLevel l = do- withCap getMiscCap \cap -> cmiAdvanceToLevel cap (+ l)---- | Wait till the provided level is reached.-advanceToLevel- :: forall caps m- . (HasCallStack, MonadCleveland caps m)- => Natural -> m ()-advanceToLevel target = do- withCap getMiscCap \cap -> cmiAdvanceToLevel cap (const target)---- | Get the timestamp observed by the last block to be baked.-getNow :: (HasCallStack, MonadCleveland caps m) => m Timestamp-getNow = do- withCap getMiscCap \cap -> cmiGetNow cap---- | Get the current level observed by the last block to be baked.-getLevel :: (HasCallStack, MonadCleveland caps m) => m Natural-getLevel = do- withCap getMiscCap \cap -> cmiGetLevel cap---- | Get approximate block interval in seconds. Note, that this value--- is minimal bound and real intervals can be larger, see--- http://tezos.gitlab.io/active/consensus.html#minimal-block-delay-function--- for more information about block delays.-getApproximateBlockInterval :: (HasCallStack, MonadCleveland caps m) => m (Time Second)-getApproximateBlockInterval = do- withCap getMiscCap \cap -> cmiGetApproximateBlockInterval cap---- | Get minimal block delay in seconds. This is essentially the same as--- 'getApproximateBlockInterval', but returns a 'Natural' instead of @Time--- Second@.------ Can be useful when testing code using @MIN_BLOCK_TIME@ instruction.-getMinBlockTime :: (HasCallStack, MonadCleveland caps m) => m Natural-getMinBlockTime = toNum @Second <$> getApproximateBlockInterval---- | Execute a contract's code without originating it.--- The chain's state will not be modified.------ Notes:------ * If the contract's code emits operations, they will not be executed.--- * The sender's account won't be debited.--- * When running an _originated_ contract, the @BALANCE@ instruction returns the--- sum of the contract's balance before the transfer operation + the amount of tz being transferred.--- In other words, this invariant holds: @BALANCE >= AMOUNT@.--- However, since `runCode` allows overriding the @BALANCE@ instruction,--- then this invariant no longer holds. It's possible that @BALANCE < AMOUNT@.-runCode- :: (HasCallStack, MonadCleveland caps m, HasRPCRepr st, IsoValue (AsRPC st))- => RunCode cp st vd -> m (AsRPC st)-runCode rc = do- sender <- view senderL- withCap getMiscCap \cap -> cmiRunCode cap sender rc---- | Execute multiple testing scenarios independently.------ * Actions performed before 'branchout' will be observed by all branches.--- * Actions performed in branches will _not_ be observed by any actions performed after 'branchout'.--- * Actions performed in one branch will _not_ be observed by another branch.--- * The test succeeds IFF all branches succeed.--- * If any branch fails, the test ends immediately and the remaining branches--- won't be executed.------ The following property holds:------ > pre >> branchout [a, b, c] = branchout [pre >> a, pre >> b, pre >> c]------ The list of branches must be non-empty.-branchout :: forall caps m. (MonadEmulated caps m) => [(Text, m ())] -> m ()-branchout branches = do- caps <- ask- let branches' :: [(Text, ClevelandBaseMonad caps ())] = second (flip runReaderT caps) <$> branches- lift $ eiBranchout (getEmulatedCap caps) branches'---- | Execute one or more actions and roll them back afterwards.--- Actions performed in 'offshoot' will _not_ be observed by any--- actions performed after 'offshoot'.------ Similar to 'branchout', but accepts one single branch.-offshoot :: forall caps m. MonadEmulated caps m => Text -> m () -> m ()-offshoot branchName branch = branchout [(branchName, branch)]--{- | Returns the result of the action with the logs it produced. Logs are messages-printed by the Lorentz instruction 'Lorentz.printComment'.--This function can be combined either with lens-based accessors or helper functions to get-more specific information about logs.--Examples:--@-(logsInfo, _) <- getMorleyLogs scenario-logsInfo ^.. each . logsL @== [MorleyLogs ["log"], MorleyLogs ["log2"]]-logsInfo ^.. each . filterLogsByAddrL addr @== [MorleyLogs ["log"]]-@--@-(logsInfo, _) <- getMorleyLogs scenario-collectLogs logsInfo @== MorleyLogs ["log", "log2"]-logsForAddress logsInfo @== [MorleyLogs ["log"]]-@---}-getMorleyLogs :: forall a caps m. MonadEmulated caps m => m a -> m (LogsInfo, a)-getMorleyLogs action = do- caps <- ask- let action' :: ClevelandBaseMonad caps a = runReaderT action caps- lift $ eiGetMorleyLogs (getEmulatedCap caps) action'---- | Version of `getMorleyLogs` for actions that don't return a result.-getMorleyLogs_ :: MonadEmulated caps m => m () -> m LogsInfo-getMorleyLogs_ action = fst <$> getMorleyLogs action---- | Updates voting power accessible via @VOTING_POWER@ and similar--- instructions.-setVotingPowers :: MonadEmulated caps m => VotingPowers -> m ()-setVotingPowers vp = do- withCap getEmulatedCap \cap -> eiSetVotingPowers cap vp---- | A helper constraint synonym to make signatures below a bit shorter-type EqBaseMonad a b = ClevelandBaseMonad a ~ ClevelandBaseMonad b---- | Perform an action if we are currently in emulation mode.--- See also 'ifEmulation' note on constraints.-whenEmulation- :: MonadCleveland caps m- => (forall caps1 m1. (EqBaseMonad caps caps1, MonadEmulated caps1 m1) => m1 ())- -> m ()-whenEmulation action = ifEmulation action pass---- | Perform an action if we are currently in network mode.--- See also 'ifEmulation' note on constraints.-whenNetwork- :: MonadCleveland caps m- => (forall caps1 m1. (EqBaseMonad caps caps1, MonadCleveland caps1 m1) => m1 ())- -> m ()-whenNetwork action = ifEmulation pass action--{- | Perform one action if we are currently in emulation mode, another otherwise--Functions passed as the first two arguments are universally quantified over-the outer monad, so if additional constraints are required beyond-'MonadEmulated' or 'MonadCleveland', those constraints have to go on the base-monad, e.g.--@-someFunction :: (MonadCleveland caps m, MonadFail (ClevelandBaseMonad caps)) => m ()-someFunction = whenEmulation do- Just x <- pure (Just 1 :: Maybe Int) -- this would error without MonadFail- runIO $ print x-@--}-ifEmulation- :: forall a caps m- . MonadCleveland caps m- => (forall caps1 m1. (EqBaseMonad caps caps1, MonadEmulated caps1 m1) => m1 a)- -> (forall caps1 m1. (EqBaseMonad caps caps1, MonadCleveland caps1 m1) => m1 a)- -> m a-ifEmulation onEmu onNet = withCap getMiscCap cmiEmulatedImpl >>= \case- Nothing -> onNet- Just impl -> withCap (view clevelandCapsL) (runReaderT onEmu . EmulatedCaps impl)--------------------------------------------------------------------------------- Assertions--------------------------------------------------------------------------------- | Fails the test with the given error message.-failure :: forall a caps m. (HasCallStack, MonadCleveland caps m) => Builder -> m a-failure msg = do- withCap getMiscCap \cap -> cmiFailure cap msg---- | Fails the test with the given error message if the given condition is false.-assert :: (HasCallStack, MonadCleveland caps m) => Bool -> Builder -> m ()-assert b errMsg =- unless b $ failure errMsg---- | @x \@== expected@ fails the test if @x@ is not equal to @expected@.-(@==)- :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a)- => a -- ^ The actual value.- -> a -- ^ The expected value.- -> m ()-actual @== expected =- assert (actual == expected) $- unlinesF- [ "Failed comparison"- , "━━ Expected (rhs) ━━"- , build expected- , "━━ Got (lhs) ━━"- , build actual- ]-infix 1 @==---- | Fails the test if the two given values are equal.-(@/=)- :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a)- => a -> a -> m ()-a @/= b =- assert (a /= b) $- unlinesF- [ "The two values are equal:"- , build a- ]-infix 1 @/=---- | Monadic version of '@=='.------ > getBalance addr @@== 10-(@@==)- :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a)- => m a -- ^ The actual value.- -> a -- ^ The expected value.- -> m ()-getActual @@== expected = do- actual <- getActual- actual @== expected-infix 1 @@==---- | Monadic version of '@/='.------ > getBalance addr @@/= 10-(@@/=)- :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a)- => m a -> a -> m ()-getA @@/= b = do- a <- getA- a @/= b-infix 1 @@/=---- | Fails the test if the comparison operator fails when applied to the given arguments.--- Prints an error message with both arguments.------ Example:------ > checkCompares 2 (>) 1-checkCompares- :: forall a b caps m- . (HasCallStack, MonadCleveland caps m, Buildable a, Buildable b)- => a- -> (a -> b -> Bool)- -> b- -> m ()-checkCompares a f b = checkComparesWith pretty a f pretty b---- | Like 'checkCompares', but with an explicit show function.--- This function does not have any constraint on the type parameters @a@ and @b@.------ For example, to print with 'Fmt.pretty':------ > checkComparesWith pretty a (<) pretty b-checkComparesWith- :: forall a b caps m- . (HasCallStack, MonadCleveland caps m)- => (a -> Text)- -> a- -> (a -> b -> Bool)- -> (b -> Text)- -> b- -> m ()-checkComparesWith showA a f showB b =- assert (f a b) $- unlinesF- [ "Failed"- , "━━ lhs ━━"- , showA a- , "━━ rhs ━━"- , showB b- ]---- | Fails the test if the `Maybe` is `Nothing`, otherwise returns the value in the `Just`.-evalJust :: (HasCallStack, MonadCleveland caps m) => Builder -> Maybe a -> m a-evalJust err = maybe (failure err) pure---- | Fails the test if the `Either` is `Left`, otherwise returns the value in the `Right`.-evalRight :: (HasCallStack, MonadCleveland caps m) => (a -> Builder) -> Either a b -> m b-evalRight mkErr = either (failure . mkErr) pure--------------------------------------------------------------------------------- Exception Handling--------------------------------------------------------------------------------- | Attempt to run an action and return its result or, if interpretation fails, an error.-attempt- :: forall e caps m a. (HasCallStack, MonadCleveland caps m, Exception e)- => m a -> m (Either e a)-attempt action = do- caps <- ask- let action' :: ClevelandBaseMonad caps a = runReaderT action caps- lift $ cmiAttempt (getMiscCap caps) action'---- | Asserts that a transfer should fail, and returns the exception.-catchTransferFailure :: (HasCallStack, MonadCleveland caps m) => m a -> m TransferFailure-catchTransferFailure action =- attempt action >>= \case- Left err -> return err- Right _ -> runIO $ throwM UnexpectedSuccess---- | Asserts that a transfer should fail, and runs some 'TransferFailurePredicate's over the--- exception.------ > expectTransferFailure (failedWith (constant @MText "NOT_ADMIN")) $--- > call contractAddr (Call @"Ep") arg------ > call contractAddr (Call @"Ep") arg & expectTransferFailure--- > ( failedWith (customError #tag 3) &&--- > addressIs contractAddr--- > )-expectTransferFailure :: (HasCallStack, MonadCleveland caps m) => TransferFailurePredicate -> m a -> m ()-expectTransferFailure predicate act = do- err <- catchTransferFailure act- checkTransferFailure err predicate---- | Check whether a given predicate holds for a given 'TransferFailure'.-checkTransferFailure :: (HasCallStack, MonadCleveland caps m) => TransferFailure -> TransferFailurePredicate -> m ()-checkTransferFailure err predicate =- case go predicate of- Success () -> pass- Failure expectedOutcome -> failure $ unlinesF- [ "Expected transfer to fail with an error such that:"- , ""- , indentF 2 $ unlinesF expectedOutcome- , ""- , "But these conditions were not met."- , "Actual transfer error:"- , indentF 2 $ build err- ]- where- go :: TransferFailurePredicate -> Validation (NonEmpty Builder) ()- go = \case- AndPredicate ps ->- first (fmtExpectedOutcomes "AND") (traverse_ go ps)- OrPredicate ps ->- case traverse_ go ps of- Success () -> Success ()- Failure expectedOutcomes ->- if length expectedOutcomes == length ps- -- If all sub-predicates failed, then this predicate failed.- then Failure $ fmtExpectedOutcomes "OR" expectedOutcomes- -- If at least 1 sub-predicate succeeded, then this predicate succeeded.- else Success ()- TransferFailurePredicate p -> first one $ p err-- fmtExpectedOutcomes :: Builder -> NonEmpty Builder -> NonEmpty Builder- fmtExpectedOutcomes delimiter = \case- expectedOutcome :| [] -> one expectedOutcome- expectedOutcomes ->- one $ unlinesF- [ "("- , indentF 2 $ unlinesF $ NE.intersperse delimiter expectedOutcomes- , ")"- ]---- | Asserts that interpretation of a contract ended with @FAILWITH@, returning the given constant--- value.-expectFailedWith- :: forall err a caps m- . (HasCallStack, MonadCleveland caps m, NiceConstant err)- => err -> m a -> m ()-expectFailedWith err = expectTransferFailure $ failedWith (constant err)---- | Asserts that interpretation of a contract ended with @FAILWITH@, returning the given lorentz--- error.-expectError- :: forall err a caps m- . (HasCallStack, MonadCleveland caps m, IsError err)- => err -> m a -> m ()-expectError err = expectTransferFailure $ failedWith (lerror err)---- | Asserts that interpretation of a contract ended with @FAILWITH@, returning the given custom--- lorentz error.-expectCustomError- :: forall arg a tag caps m- . ( HasCallStack, MonadCleveland caps m- , IsError (CustomError tag)- , MustHaveErrorArg tag (MText, arg)- )- => Label tag -> arg -> m a -> m ()-expectCustomError tag arg = expectTransferFailure $ failedWith (customError tag arg)---- | Version of 'expectCustomError' for error with @unit@ argument.-expectCustomError_- :: ( HasCallStack, MonadCleveland caps m- , IsError (CustomError tag)- , MustHaveErrorArg tag (MText, ())- )- => Label tag -> m a -> m ()-expectCustomError_ tag = expectCustomError tag ()---- | Version of 'expectCustomError' specialized for expecting @NoErrorArg@s.-expectCustomErrorNoArg- :: ( HasCallStack, MonadCleveland caps m- , IsError (CustomError tag)- , MustHaveErrorArg tag MText- )- => Label tag -> m a -> m ()-expectCustomErrorNoArg tag = expectTransferFailure $ failedWith (customErrorNoArg tag)---- | Asserts that interpretation of a contract ended with @FAILWITH@, returning the given lorentz--- numeric error.-expectNumericError- :: forall err a caps m- . (HasCallStack, MonadCleveland caps m, IsError err)- => ErrorTagMap -> err -> m a -> m ()-expectNumericError tagMap err = expectTransferFailure $ failedWith (numericError tagMap err)---- | Prefix /scenario-custom/ error messages (i.e. @CustomTestError@ either from pure or non-pure--- implementation), potentially thrown from the given code block.------ The prefix will be put at a separate line before the main text, if text is multiline, otherwise--- it will be separated from the main text with @: @.------ This affects errors produced by functions like 'failure', 'assert', '@==', etc.--- Errors related to events in the chain will not be touched.------ Example:------ > for [1..10] \i -> clarifyErrors ("For i=" +| i |+ "") $--- > askContract i @@== i * 2-clarifyErrors :: forall caps m a. (MonadCleveland caps m)- => Builder -> m a -> m a-clarifyErrors message action = do- attempt action >>= \case- Left (e :: SomeException) -> withCap getMiscCap \cap -> cmiThrow cap (handle e)- Right val -> pure val- where- handle :: SomeException -> SomeException- handle e = fromMaybe e $- wrap testClientErrorHandler e- <|> wrap testPureErrorHandler e- <|> wrap withCallStackErrorHandler e-- wrap f = fmap (toException . f) . fromException-- addPrefix = pretty . nameF message . build-- testClientErrorHandler :: Client.TestError -> Client.TestError- testClientErrorHandler = \case- Client.CustomTestError msg -> Client.CustomTestError $ addPrefix msg-- testPureErrorHandler :: Pure.TestError -> Pure.TestError- testPureErrorHandler = \case- Pure.CustomTestError msg -> Pure.CustomTestError $ addPrefix msg- err -> err-- withCallStackErrorHandler :: WithCallStack -> WithCallStack- withCallStackErrorHandler (WithCallStack cst e) = WithCallStack cst $ handle e--------------------------------------------------------------------------------- TransferFailure Predicates--------------------------------------------------------------------------------- | A predicate that checks whether a transfer operation failed for the expected reason.------ Predicates can be combined using the '&&' and '||' operators.-data TransferFailurePredicate- = TransferFailurePredicate- (TransferFailure -> Validation Builder ())- -- ^ A predicate that either returns () or, if it fails,- -- a message explaining what the expected outcome was.- | AndPredicate (NonEmpty TransferFailurePredicate)- | OrPredicate (NonEmpty TransferFailurePredicate)--instance Boolean TransferFailurePredicate where- AndPredicate l && AndPredicate r = AndPredicate $ l <> r- AndPredicate l && r = AndPredicate $ l <> one r- l && AndPredicate r = AndPredicate $ one l <> r- l && r = AndPredicate $ one l <> one r-- OrPredicate l || OrPredicate r = OrPredicate $ l <> r- OrPredicate l || r = OrPredicate $ l <> one r- l || OrPredicate r = OrPredicate $ one l <> r- l || r = OrPredicate $ one l <> one r--transferFailureReasonPredicate- :: (TransferFailureReason -> Validation Builder ())- -> TransferFailurePredicate-transferFailureReasonPredicate p = TransferFailurePredicate $- \(TransferFailure _ reason) -> p reason---- | Asserts that interpretation of a contract failed due to an overflow error.-shiftOverflow :: TransferFailurePredicate-shiftOverflow = transferFailureReasonPredicate \case- ShiftOverflow -> pass- _ -> Failure "Contract failed due to an overflow error"---- | Asserts that an action failed due to an attempt to transfer 0tz towards a simple address.-emptyTransaction :: TransferFailurePredicate-emptyTransaction = transferFailureReasonPredicate \case- EmptyTransaction -> pass- _ -> Failure "Attempted to transfer 0tz to a simple address"---- | Asserts that an action failed due to an attempt to call a contract with an invalid parameter.-badParameter :: TransferFailurePredicate-badParameter = transferFailureReasonPredicate \case- BadParameter -> pass- _ -> Failure "Attempted to call a contract with a parameter of the wrong type"---- | Asserts that interpretation of a contract failed due to gas exhaustion.-gasExhaustion :: TransferFailurePredicate-gasExhaustion = transferFailureReasonPredicate \case- GasExhaustion -> pass- _ -> Failure "Execution failed due to gas exhaustion"---- | Asserts that interpretation of a contract ended with @FAILWITH@, throwing the given error.------ This function should be used together with one of the "@FAILWITH@ constructors"--- (e.g. 'constant', 'customError').-failedWith :: SomeConstant -> TransferFailurePredicate-failedWith expectedFailWithVal = transferFailureReasonPredicate \case- FailedWith (EOTVExpression actualFailWithExpr) _- | actualFailWithExpr `isEq` expectedFailWithVal -> pass- FailedWith (EOTVTypedValue actualFailWithVal) _- | toExpression actualFailWithVal `isEq` expectedFailWithVal -> pass- _ -> Failure $ "Contract failed with: " <> buildRenderDoc expectedFailWithVal- where- isEq :: Expression -> SomeConstant -> Bool- isEq expr (SomeConstant (v :: T.Value t)) =- either (const False) (== v) (fromExpression @(T.Value t) expr)---- | Asserts that the error occurred while interpreting the contract with the given address.-addressIs- :: ToAddress addr- => addr -- ^ The expected address.- -> TransferFailurePredicate-addressIs (toAddress -> expectedAddr) = TransferFailurePredicate \err -> do- let TransferFailure actualAddr _ = err- when (actualAddr /= expectedAddr) $- Failure $ "Failure occurred in contract with address: " <> build expectedAddr--------------------------------------------------------------------------------- 'FAILWITH' errors--------------------------------------------------------------------------------- | A constant michelson value that a contract threw with @FAILWITH@.-constant :: forall err. NiceConstant err => err -> SomeConstant-constant err =- withDict (niceConstantEvi @err) $- SomeConstant $ toVal err---- | A lorentz error.-lerror :: forall err. IsError err => err -> SomeConstant-lerror err = errorToVal err SomeConstant---- | A custom lorentz error.-customError- :: forall arg tag. (IsError (CustomError tag), MustHaveErrorArg tag (MText, arg))- => Label tag -> arg -> SomeConstant-customError tag arg =- lerror $ CustomError tag (errorTagToMText tag, arg)---- | A custom lorentz error with a @unit@ argument.-customError_- :: (IsError (CustomError tag), MustHaveErrorArg tag (MText, ()))- => Label tag -> SomeConstant-customError_ tag = customError tag ()---- | A custom lorentz error with no argument.-customErrorNoArg- :: (IsError (CustomError tag), MustHaveErrorArg tag MText)- => Label tag -> SomeConstant-customErrorNoArg tag =- lerror $ CustomError tag (errorTagToMText tag)---- | A lorentz numeric error.-numericError :: forall err. IsError err => ErrorTagMap -> err -> SomeConstant-numericError tagMap err = errorToValNumeric tagMap err SomeConstant--------------------------------------------------------------------------------- Internal helpers-------------------------------------------------------------------------------withCap :: Monad m => (caps -> cap) -> (cap -> m a) -> ReaderT caps m a-withCap getCap useCap = do- cap <- asks getCap- lift $ useCap cap---- | Common conversion function from 'OriginateData' to 'UntypedOriginateData'-originateDataToUntyped :: OriginateData param st vd -> UntypedOriginateData-originateDataToUntyped OriginateData{ odContract = contract@Contract{}, .. } =- UntypedOriginateData- { uodName = odName- , uodBalance = odBalance- , uodStorage = untypeHelper odStorage- , uodContract = convertContract $ toMichelsonContract contract- }--untypeHelper :: forall st. NiceStorage st => st -> U.Value-untypeHelper = untypeValue . toVal \\ niceStorageEvi @st+ ( MonadOps+ , MonadTransfer+ , MonadOriginate+ , withSender+ , withMoneybag+ , runIO+ , resolveAddress+ , refillable+ , newAddress+ , newAddresses+ , newFreshAddress+ , enumAliases+ , signBytes+ , signBinary+ , originate+ , Large (..)+ , transfer+ , WithContractEvents (..)+ , calling+ , unsafeCalling+ , inBatch+ , importUntypedContract+ , importContract+ , noViews+ , comment+ , getBalance+ , getStorage+ , getFullStorage+ , getSomeStorage+ , getAllBigMapValues+ , getAllBigMapValuesMaybe+ , getBigMapSize+ , getBigMapSizeMaybe+ , getBigMapValueMaybe+ , getBigMapValue+ , getMorleyLogs+ , getMorleyLogs_+ , getPublicKey+ , getChainId+ , advanceTime+ , advanceLevel+ , advanceToLevel+ , getNow+ , getLevel+ , getApproximateBlockInterval+ , getMinBlockTime+ , runCode+ , branchout+ , offshoot+ , getDelegate+ , registerDelegate+ , setVotingPowers+ , whenEmulation+ , whenNetwork+ , ifEmulation+ , getMorleyClientEnv++ -- * Assertions+ , failure+ , assert+ , (@==)+ , (@/=)+ , (@@==)+ , (@@/=)+ , checkCompares+ , checkComparesWith+ , evalJust+ , evalRight++ -- * Exception handling+ , attempt+ , catchTransferFailure+ , checkTransferFailure+ , expectTransferFailure+ , expectFailedWith+ , expectError+ , expectCustomError+ , expectCustomError_+ , expectCustomErrorNoArg+ , expectNumericError+ , clarifyErrors+ -- ** TransferFailure predicates+ , TransferFailurePredicate(..)+ , shiftOverflow+ , emptyTransaction+ , badParameter+ , gasExhaustion+ , failedWith+ , addressIs+ -- ** @FAILWITH@ errors+ , constant+ , lerror+ , customError+ , customError_+ , customErrorNoArg+ , numericError+ ) where++import Test.Cleveland.Internal.Actions.Assertions+import Test.Cleveland.Internal.Actions.ExceptionHandling+import Test.Cleveland.Internal.Actions.Misc+import Test.Cleveland.Internal.Actions.Originate+import Test.Cleveland.Internal.Actions.Transfer+import Test.Cleveland.Internal.Actions.TransferFailurePredicate++-- | Synonym typeclass for monads where network operations can occur.+--+-- This has instances for @MonadCleveland@ and @ClevelandOpsBatch@ contexts.+--+-- Practically, if you want to use 'transfer' or 'originate' in a monad, add a+-- 'MonadOps' constraint on it, f. ex.:+--+-- > callEp1 :: MonadOps m => ContractHandle MyParam () () -> Integer -> m ()+-- > callEp1 ch = transfer ch . calling (ep @"Entrypoint1")+class (MonadTransfer m, MonadOriginate m) => MonadOps m+instance (MonadTransfer m, MonadOriginate m) => MonadOps m++-- Note: 'MonadOps' is a typeclass and not a constraint synonym because GHC (as+-- of 9.0) is being silly and complaining about impredicative polymorphism when+-- defining a constraint synonym with quantified constraints.
+ src/Test/Cleveland/Internal/Actions/Assertions.hs view
@@ -0,0 +1,125 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++-- | Various test assertions in the 'MonadCleveland' context.+module Test.Cleveland.Internal.Actions.Assertions+ ( module Test.Cleveland.Internal.Actions.Assertions+ ) where++import Fmt (Buildable, Builder, build, pretty, unlinesF)++import Test.Cleveland.Internal.Abstract+import Test.Cleveland.Internal.Actions.Helpers++{-# ANN module ("HLint: ignore Avoid lambda using `infix`" :: Text) #-}++-- | Fails the test with the given error message.+failure :: forall a caps m. (HasCallStack, MonadCleveland caps m) => Builder -> m a+failure msg = do+ withCap getMiscCap \cap -> cmiFailure cap msg++-- | Fails the test with the given error message if the given condition is false.+assert :: (HasCallStack, MonadCleveland caps m) => Bool -> Builder -> m ()+assert b errMsg =+ unless b $ failure errMsg++-- | @x \@== expected@ fails the test if @x@ is not equal to @expected@.+(@==)+ :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a)+ => a -- ^ The actual value.+ -> a -- ^ The expected value.+ -> m ()+actual @== expected =+ assert (actual == expected) $+ unlinesF+ [ "Failed comparison"+ , "━━ Expected (rhs) ━━"+ , build expected+ , "━━ Got (lhs) ━━"+ , build actual+ ]+infix 1 @==++-- | Fails the test if the two given values are equal.+(@/=)+ :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a)+ => a -> a -> m ()+a @/= b =+ assert (a /= b) $+ unlinesF+ [ "The two values are equal:"+ , build a+ ]+infix 1 @/=++-- | Monadic version of '@=='.+--+-- > getBalance addr @@== 10+(@@==)+ :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a)+ => m a -- ^ The actual value.+ -> a -- ^ The expected value.+ -> m ()+getActual @@== expected = do+ actual <- getActual+ actual @== expected+infix 1 @@==++-- | Monadic version of '@/='.+--+-- > getBalance addr @@/= 10+(@@/=)+ :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a)+ => m a -> a -> m ()+getA @@/= b = do+ a <- getA+ a @/= b+infix 1 @@/=++-- | Fails the test if the comparison operator fails when applied to the given arguments.+-- Prints an error message with both arguments.+--+-- Example:+--+-- > checkCompares 2 (>) 1+checkCompares+ :: forall a b caps m+ . (HasCallStack, MonadCleveland caps m, Buildable a, Buildable b)+ => a+ -> (a -> b -> Bool)+ -> b+ -> m ()+checkCompares a f b = checkComparesWith pretty a f pretty b++-- | Like 'checkCompares', but with an explicit show function.+-- This function does not have any constraint on the type parameters @a@ and @b@.+--+-- For example, to print with 'Fmt.pretty':+--+-- > checkComparesWith pretty a (<) pretty b+checkComparesWith+ :: forall a b caps m+ . (HasCallStack, MonadCleveland caps m)+ => (a -> Text)+ -> a+ -> (a -> b -> Bool)+ -> (b -> Text)+ -> b+ -> m ()+checkComparesWith showA a f showB b =+ assert (f a b) $+ unlinesF+ [ "Failed"+ , "━━ lhs ━━"+ , showA a+ , "━━ rhs ━━"+ , showB b+ ]++-- | Fails the test if the `Maybe` is `Nothing`, otherwise returns the value in the `Just`.+evalJust :: (HasCallStack, MonadCleveland caps m) => Builder -> Maybe a -> m a+evalJust err = maybe (failure err) pure++-- | Fails the test if the `Either` is `Left`, otherwise returns the value in the `Right`.+evalRight :: (HasCallStack, MonadCleveland caps m) => (a -> Builder) -> Either a b -> m b+evalRight mkErr = either (failure . mkErr) pure
+ src/Test/Cleveland/Internal/Actions/ExceptionHandling.hs view
@@ -0,0 +1,188 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++-- | Exception handling+module Test.Cleveland.Internal.Actions.ExceptionHandling+ ( module Test.Cleveland.Internal.Actions.ExceptionHandling+ ) where++import Data.Either.Validation (Validation(..))+import Data.List.NonEmpty qualified as NE+import Fmt (Builder, build, indentF, nameF, pretty, unlinesF)++import Lorentz (CustomError(..), ErrorTagMap, IsError, Label, MText, MustHaveErrorArg)+import Lorentz.Constraints+import Test.Cleveland.Internal.Abstract+import Test.Cleveland.Internal.Actions.Assertions+import Test.Cleveland.Internal.Actions.Helpers+import Test.Cleveland.Internal.Actions.Misc+import Test.Cleveland.Internal.Actions.TransferFailurePredicate+import Test.Cleveland.Internal.Client qualified as Client (TestError(..))+import Test.Cleveland.Internal.Exceptions (WithCallStack(..))+import Test.Cleveland.Internal.Pure as Pure (TestError(..))++-- | Attempt to run an action and return its result or, if interpretation fails, an error.+attempt+ :: forall e caps m a. (HasCallStack, MonadCleveland caps m, Exception e)+ => m a -> m (Either e a)+attempt action = do+ caps <- ask+ let action' :: ClevelandBaseMonad caps a = runReaderT action caps+ lift $ cmiAttempt (getMiscCap caps) action'++-- | Asserts that a transfer should fail, and returns the exception.+catchTransferFailure :: (HasCallStack, MonadCleveland caps m) => m a -> m TransferFailure+catchTransferFailure action =+ attempt action >>= \case+ Left err -> return err+ Right _ -> runIO $ throwM UnexpectedSuccess++-- | Asserts that a transfer should fail, and runs some 'TransferFailurePredicate's over the+-- exception.+--+-- > expectTransferFailure (failedWith (constant @MText "NOT_ADMIN")) $+-- > call contractAddr (Call @"Ep") arg+--+-- > call contractAddr (Call @"Ep") arg & expectTransferFailure+-- > ( failedWith (customError #tag 3) &&+-- > addressIs contractAddr+-- > )+expectTransferFailure :: (HasCallStack, MonadCleveland caps m) => TransferFailurePredicate -> m a -> m ()+expectTransferFailure predicate act = do+ err <- catchTransferFailure act+ checkTransferFailure err predicate++-- | Check whether a given predicate holds for a given 'TransferFailure'.+checkTransferFailure :: (HasCallStack, MonadCleveland caps m) => TransferFailure -> TransferFailurePredicate -> m ()+checkTransferFailure err predicate =+ case go predicate of+ Success () -> pass+ Failure expectedOutcome -> failure $ unlinesF+ [ "Expected transfer to fail with an error such that:"+ , ""+ , indentF 2 $ unlinesF expectedOutcome+ , ""+ , "But these conditions were not met."+ , "Actual transfer error:"+ , indentF 2 $ build err+ ]+ where+ go :: TransferFailurePredicate -> Validation (NonEmpty Builder) ()+ go = \case+ AndPredicate ps ->+ first (fmtExpectedOutcomes "AND") (traverse_ go ps)+ OrPredicate ps ->+ case traverse_ go ps of+ Success () -> Success ()+ Failure expectedOutcomes ->+ if length expectedOutcomes == length ps+ -- If all sub-predicates failed, then this predicate failed.+ then Failure $ fmtExpectedOutcomes "OR" expectedOutcomes+ -- If at least 1 sub-predicate succeeded, then this predicate succeeded.+ else Success ()+ TransferFailurePredicate p -> first one $ p err++ fmtExpectedOutcomes :: Builder -> NonEmpty Builder -> NonEmpty Builder+ fmtExpectedOutcomes delimiter = \case+ expectedOutcome :| [] -> one expectedOutcome+ expectedOutcomes ->+ one $ unlinesF+ [ "("+ , indentF 2 $ unlinesF $ NE.intersperse delimiter expectedOutcomes+ , ")"+ ]++-- | Asserts that interpretation of a contract ended with @FAILWITH@, returning the given constant+-- value.+expectFailedWith+ :: forall err a caps m+ . (HasCallStack, MonadCleveland caps m, NiceConstant err)+ => err -> m a -> m ()+expectFailedWith err = expectTransferFailure $ failedWith (constant err)++-- | Asserts that interpretation of a contract ended with @FAILWITH@, returning the given lorentz+-- error.+expectError+ :: forall err a caps m+ . (HasCallStack, MonadCleveland caps m, IsError err)+ => err -> m a -> m ()+expectError err = expectTransferFailure $ failedWith (lerror err)++-- | Asserts that interpretation of a contract ended with @FAILWITH@, returning the given custom+-- lorentz error.+expectCustomError+ :: forall arg a tag caps m+ . ( HasCallStack, MonadCleveland caps m+ , IsError (CustomError tag)+ , MustHaveErrorArg tag (MText, arg)+ )+ => Label tag -> arg -> m a -> m ()+expectCustomError tag arg = expectTransferFailure $ failedWith (customError tag arg)++-- | Version of 'expectCustomError' for error with @unit@ argument.+expectCustomError_+ :: ( HasCallStack, MonadCleveland caps m+ , IsError (CustomError tag)+ , MustHaveErrorArg tag (MText, ())+ )+ => Label tag -> m a -> m ()+expectCustomError_ tag = expectCustomError tag ()++-- | Version of 'expectCustomError' specialized for expecting @NoErrorArg@s.+expectCustomErrorNoArg+ :: ( HasCallStack, MonadCleveland caps m+ , IsError (CustomError tag)+ , MustHaveErrorArg tag MText+ )+ => Label tag -> m a -> m ()+expectCustomErrorNoArg tag = expectTransferFailure $ failedWith (customErrorNoArg tag)++-- | Asserts that interpretation of a contract ended with @FAILWITH@, returning the given lorentz+-- numeric error.+expectNumericError+ :: forall err a caps m+ . (HasCallStack, MonadCleveland caps m, IsError err)+ => ErrorTagMap -> err -> m a -> m ()+expectNumericError tagMap err = expectTransferFailure $ failedWith (numericError tagMap err)++-- | Prefix /scenario-custom/ error messages (i.e. @CustomTestError@ either from pure or non-pure+-- implementation), potentially thrown from the given code block.+--+-- The prefix will be put at a separate line before the main text, if text is multiline, otherwise+-- it will be separated from the main text with @: @.+--+-- This affects errors produced by functions like 'failure', 'assert', '@==', etc.+-- Errors related to events in the chain will not be touched.+--+-- Example:+--+-- > for [1..10] \i -> clarifyErrors ("For i=" +| i |+ "") $+-- > askContract i @@== i * 2+clarifyErrors :: forall caps m a. (MonadCleveland caps m)+ => Builder -> m a -> m a+clarifyErrors message action = do+ attempt action >>= \case+ Left (e :: SomeException) -> withCap getMiscCap \cap -> cmiThrow cap (handle e)+ Right val -> pure val+ where+ handle :: SomeException -> SomeException+ handle e = fromMaybe e $+ wrap testClientErrorHandler e+ <|> wrap testPureErrorHandler e+ <|> wrap withCallStackErrorHandler e++ wrap f = fmap (toException . f) . fromException++ addPrefix = pretty . nameF message . build++ testClientErrorHandler :: Client.TestError -> Client.TestError+ testClientErrorHandler = \case+ Client.CustomTestError msg -> Client.CustomTestError $ addPrefix msg++ testPureErrorHandler :: Pure.TestError -> Pure.TestError+ testPureErrorHandler = \case+ Pure.CustomTestError msg -> Pure.CustomTestError $ addPrefix msg+ err -> err++ withCallStackErrorHandler :: WithCallStack -> WithCallStack+ withCallStackErrorHandler (WithCallStack cst e) = WithCallStack cst $ handle e
+ src/Test/Cleveland/Internal/Actions/Helpers.hs view
@@ -0,0 +1,12 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++-- | Helpers for working in @MonadCleveland@ context.+module Test.Cleveland.Internal.Actions.Helpers+ ( module Test.Cleveland.Internal.Actions.Helpers+ ) where++withCap :: Monad m => (caps -> cap) -> (cap -> m a) -> ReaderT caps m a+withCap getCap useCap = do+ cap <- asks getCap+ lift $ useCap cap
+ src/Test/Cleveland/Internal/Actions/Misc.hs view
@@ -0,0 +1,552 @@+-- SPDX-FileCopyrightText: 2021 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++-- | The bulk of Cleveland actions.+module Test.Cleveland.Internal.Actions.Misc+ ( module Test.Cleveland.Internal.Actions.Misc+ , noViews+ ) where++import Data.Singletons (demote)+import Fmt (Buildable, Builder, build, indentF, unlinesF, (+|), (|+))+import Time (KnownDivRat, Second, Time, toNum)+import Unsafe qualified (fromIntegral)++import Lorentz (BigMapId, Contract(..), DemoteViewsDescriptor, IsoValue, noViews)+import Lorentz.Bytes+import Lorentz.Constraints+import Morley.AsRPC (HasRPCRepr(..))+import Morley.Client (MorleyClientEnv)+import Morley.Michelson.Runtime (VotingPowers)+import Morley.Michelson.Runtime.Import qualified as Runtime+import Morley.Michelson.Typed (SomeAnnotatedValue)+import Morley.Michelson.Typed qualified as T+import Morley.Michelson.Typed.AnnotatedValue (castTo, getT, value)+import Morley.Michelson.Untyped qualified as U+import Morley.Tezos.Address.Alias (Alias(..))+import Morley.Tezos.Core (ChainId, Mutez, Timestamp)+import Morley.Tezos.Crypto (KeyHash, PublicKey, Signature)+import Morley.Util.SizedList qualified as SL+import Morley.Util.SizedList.Types+import Test.Cleveland.Instances ()+import Test.Cleveland.Internal.Abstract+import Test.Cleveland.Internal.Actions.Assertions+import Test.Cleveland.Internal.Actions.Helpers+import Test.Cleveland.Internal.Actions.Transfer+import Test.Cleveland.Lorentz.Import qualified as LorentzImport+import Test.Cleveland.Lorentz.Types++{-# ANN module ("HLint: ignore Avoid lambda using `infix`" :: Text) #-}++-- $setup+-- >>> :m +Morley.Util.SizedList.Types+-- >>> :{+-- isEquivalentTo :: Show a => a -> a -> Bool+-- isEquivalentTo a b = Debug.show a == Debug.show b+-- infix 0 `isEquivalentTo`+-- :}++-- | Update the current sender on whose behalf transfers and originations are+-- invoked.+withSender :: MonadCleveland caps m => ImplicitAddress -> m a -> m a+withSender addr =+ local (set senderL (Sender addr))++-- | Update the current moneybag that transfers money on the newly created+-- addresses. For the rare occasions when this is necessary.+withMoneybag :: MonadCleveland caps m => ImplicitAddress -> m a -> m a+withMoneybag addr =+ local (set moneybagL (Moneybag addr))++-- | Runs an 'IO' action.+runIO :: (HasCallStack, MonadCleveland caps m) => IO res -> m res+runIO io = do+ withCap getMiscCap \cap -> cmiRunIO cap io++-- | Get the address of the implicit account / contract associated with the given alias.+resolveAddress+ :: (HasCallStack, MonadCleveland caps m)+ => Alias kind -> m (KindedAddress kind)+resolveAddress alias = do+ withCap getMiscCap \cap -> cmiResolveAddress cap alias++-- | Simple combinator that marks address as "refillable".+--+-- If a refillable address lacks funds for the next operation,+-- some funds will automatically be transferred to it.+refillable :: MonadCleveland caps m => m ImplicitAddress -> m ImplicitAddress+refillable action = do+ addr <- action+ withCap getMiscCap \cap -> cmiMarkAddressRefillable cap addr+ pure addr++-- | If the given alias is already associated with an existing address,+-- that address will be reused and returned.+-- Otherwise, generate a new secret key and record it with given alias.+--+-- If the account has too low of a balance, a small amount of XTZ will+-- be transferred to it.+--+-- Notes:+--+-- * By default, the XTZ is transferred from the account associated with the @moneybag@ alias.+-- This can be overridden with the @--cleveland-moneybag-alias@ command line option, the+-- @TASTY_CLEVELAND_MONEYBAG_ALIAS@ env var, or 'withMoneybag'.+newAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAlias -> m ImplicitAddress+newAddress alias = do+ addrs <- newAddresses $ alias :< Nil+ case addrs of+ addr :< Nil -> pure addr++-- | Batched version of `newAddress`+newAddresses+ :: forall n n' caps m.+ (HasCallStack, MonadCleveland caps m, IsoNatPeano n n')+ => SizedList n SpecificOrDefaultAlias+ -> m (SizedList n ImplicitAddress)+newAddresses aliases = do+ addrs <- withCap getMiscCap \cap -> traverse (cmiGenKey cap) aliases+ Moneybag moneybag <- view moneybagL++ -- Addresses may exist from previous scenarios runs and have sufficient+ -- balance for the sake of testing; if so, we can save some time+ balances <- traverse getBalance addrs+ withSender moneybag do+ inBatch do+ sequenceA_ $+ SL.zipWith refillIfLowBalance addrs balances++ pure addrs+ where+ refillIfLowBalance addr balance =+ when (balance < 0.5_e6) do -- < 0.5 XTZ+ transfer addr (0.9_e6 :: Mutez) -- 0.9 XTZ++-- | Generate a new secret key and record it with given alias. If the+-- alias is already known, the key will be overwritten. The address is+-- guaranteed to be fresh, i. e. no operations on it have been made.+newFreshAddress+ :: (HasCallStack, MonadCleveland caps m)+ => SpecificOrDefaultAlias -> m ImplicitAddress+newFreshAddress alias = do+ withCap getMiscCap \cap -> cmiGenFreshKey cap alias++-- | Get the signature of the preapplied operation.+signBytes :: (HasCallStack, MonadCleveland caps m) => ByteString -> ImplicitAddress -> m Signature+signBytes bytes signer = do+ withCap getMiscCap \cap -> cmiSignBytes cap bytes signer++-- | Create a list of similarly named 'SpecificAlias'es.+--+-- For example,+--+-- >>> enumAliases @2 "operator" `isEquivalentTo` "operator-0" :< "operator-1" :< Nil+-- True+enumAliases+ :: forall n n'.+ (SingIPeano n, IsoNatPeano n n')+ => ImplicitAlias -> SizedList n SpecificOrDefaultAlias+enumAliases (ImplicitAlias pfx) =+ SpecificAlias <$> SL.generate @n (\n -> ImplicitAlias $ pfx <> "-" <> show n)++-- | Type-safer version of 'signBytes'.+signBinary+ :: (HasCallStack, BytesLike bs, MonadCleveland caps m)+ => bs -> ImplicitAddress -> m (TSignature bs)+signBinary bs addr = TSignature <$> signBytes (toBytes bs) addr++-- | Import an untyped contract from file.+importUntypedContract :: (HasCallStack, MonadCleveland caps m) => FilePath -> m U.Contract+importUntypedContract = runIO . Runtime.importUntypedContract++-- | Import a contract from file.+--+-- The compiler must be able to infer the types of parameter, storage and views.+-- In case there are no views or you don't care, you can use 'noViews'.+importContract+ :: ( HasCallStack, NiceParameter param, NiceStorage st+ , NiceViewsDescriptor vd, DemoteViewsDescriptor vd+ , MonadCleveland caps m+ )+ => FilePath -> m (Contract param st vd)+importContract = runIO . LorentzImport.importContract++{- | Run operations in a batch.+Best used with the @ApplicativeDo@ GHC extension.++Example:++@+{-# LANGUAGE ApplicativeDo #-}++contract <- inBatch $ do+ contract <- originate ...+ for_ [1..3] \i ->+ transfer ...+ return contract+@++Batched operations should be applied to chain faster, but note that batches have+their own limits. For instance, at the moment of writing, the gas limit on a+batch is 10x of gas limit applied to a single operation.++A context of a batch is only 'Applicative', not 'Monad'. This means that:++* Return values of one function cannot be passed to another function in the same+ batch, it can only be returned;+* Sometimes the compiler does not recognize that only 'Applicative' context is+ required, in case of any issues with that - follow the error messages.++-}+inBatch :: (HasCallStack, MonadCleveland caps m) => ClevelandOpsBatch a -> m a+inBatch batch = do+ withCap getOpsCap \cap -> runBatched cap batch++-- | Print the given string verbatim as a comment.+-- At the moment, this is a no-op in emulator tests.+comment :: (HasCallStack, MonadCleveland caps m) => Text -> m ()+comment cmt = do+ withCap getMiscCap \cap -> cmiComment cap cmt++-- | Get the balance of the given address.+getBalance+ :: (HasCallStack, MonadCleveland caps m, ToL1Address addr)+ => addr -> m Mutez+getBalance addr = do+ withCap getMiscCap \cap -> cmiGetBalance cap (toL1Address addr)++-- | Get the delegate for the given contract. Fails on implicit contracts.+getDelegate+ :: (HasCallStack, MonadCleveland caps m, ToContractAddress addr)+ => addr -> m (Maybe KeyHash)+getDelegate addr = do+ withCap getMiscCap \cap -> cmiGetDelegate cap (toContractAddress addr)++-- | Register the given address as a valid delegate.+registerDelegate :: (HasCallStack, MonadCleveland caps m) => ImplicitAddress -> m ()+registerDelegate addr = do+ withCap getMiscCap \cap -> cmiRegisterDelegate cap addr++-- | Retrieve a contract's storage in its "RPC representation"+-- (i.e., all its big_maps will be replaced by big_map IDs).+--+-- If the storage is of a user-defined type, then 'Test.Cleveland.deriveRPC' /+-- 'Test.Cleveland.deriveManyRPC' should be used to create an RPC representation of the storage+-- type.+--+-- > data MyStorage = MyStorage { field1 :: Natural, field2 :: BigMap Integer MText }+-- > deriveRPC "MyStorage"+getStorage+ :: forall st addr caps m.+ (HasCallStack, MonadCleveland caps m, ToStorageType st addr, IsoValue (AsRPC st))+ => addr+ -> m (AsRPC st)+getStorage contract = do+ someSt <- getSomeStorage contract+ case someSt ^? castTo @(AsRPC st) . value of+ Just st -> pure st+ Nothing -> failure $ unlinesF+ [ "Expected storage to be of type:"+ , indentF 2 $ build $ demote @(T.ToT (AsRPC st))+ , "But its type was:"+ , indentF 2 $ build $ getT someSt+ ]++-- | Retrieve a contract's full storage, including the contents of its big_maps.+--+-- This function can only be used in emulator-only tests.+getFullStorage+ :: forall st addr caps m.+ (HasCallStack, MonadEmulated caps m, ToStorageType st addr)+ => addr+ -> m st+getFullStorage contract = do+ withCap getEmulatedCap \cap -> eiGetStorage cap contract++-- | Similar to 'getStorage', but doesn't require knowing+-- the storage type in advance.+--+-- Use the optics in 'Morley.Michelson.Typed.AnnotatedValue' to+-- read data from the storage.+getSomeStorage+ :: forall addr caps m.+ (HasCallStack, MonadCleveland caps m, ToContractAddress addr)+ => addr+ -> m SomeAnnotatedValue+getSomeStorage contract = do+ withCap getMiscCap \cap -> cmiGetSomeStorage cap (toContractAddress contract)++-- | Retrieve a big_map value, given a big_map ID and a key.+-- Returns 'Nothing' when the big_map ID does not exist, or it exists but+-- does not contain the given key.+getBigMapValueMaybe+ :: forall k v caps m.+ ( HasCallStack, MonadCleveland caps m+ , NiceComparable k, NicePackedValue k, NiceUnpackedValue v+ )+ => BigMapId k v -> k -> m (Maybe v)+getBigMapValueMaybe bmId key = do+ withCap getMiscCap \cap -> cmiGetBigMapValueMaybe cap bmId key++-- | Like 'getBigMapValueMaybe', but fails the tests instead of returning 'Nothing'.+getBigMapValue+ :: forall k v caps m.+ ( HasCallStack, MonadCleveland caps m+ , NiceComparable k, NicePackedValue k, NiceUnpackedValue v+ , Buildable k+ )+ => BigMapId k v -> k -> m v+getBigMapValue bmId k =+ getBigMapValueMaybe bmId k >>= \case+ Just v -> pure v+ Nothing -> failure $ unlinesF @_ @Builder+ [ "Either:"+ , " 1. A big_map with ID '" +| bmId |+ "' does not exist, or"+ , " 2. It exists, but does not contain the key '" +| k |+ "'."+ ]++-- | Retrieve all big_map values, given a big_map ID.+-- Returns 'Nothing' when the big_map ID does not exist.+getAllBigMapValuesMaybe+ :: forall k v caps m.+ ( HasCallStack, MonadCleveland caps m+ , NiceComparable k, NiceUnpackedValue v+ )+ => BigMapId k v -> m (Maybe [v])+getAllBigMapValuesMaybe bmId = do+ withCap getMiscCap \cap -> cmiGetAllBigMapValuesMaybe cap bmId++-- | Like 'getAllBigMapValuesMaybe', but fails the tests instead of returning 'Nothing'.+getAllBigMapValues+ :: forall k v caps m.+ ( HasCallStack, MonadCleveland caps m+ , NiceComparable k, NiceUnpackedValue v+ )+ => BigMapId k v -> m [v]+getAllBigMapValues bmId =+ getAllBigMapValuesMaybe bmId >>= \case+ Just vs -> pure vs+ Nothing -> failure $ "A big map with ID '" +| bmId |+ "' does not exist"++-- | Retrieve a big_map size, given a big_map ID.+-- Returns 'Nothing' when the big_map ID does not exist.+--+-- /O(n)/, because it's implemented with 'Morley.Client.RPC.Getters.getBigMapValues'.+getBigMapSizeMaybe+ :: forall k v caps m.+ ( HasCallStack, MonadCleveland caps m+ , NiceComparable k, NiceUnpackedValue v+ )+ => BigMapId k v -> m (Maybe Natural)+getBigMapSizeMaybe bmId =+ fmap (fmap (Unsafe.fromIntegral @Int @Natural . length)) (getAllBigMapValuesMaybe bmId)++-- | Like 'getBigMapSizeMaybe', but fails the tests instead of returning 'Nothing'.+getBigMapSize+ :: forall k v caps m.+ ( HasCallStack, MonadCleveland caps m+ , NiceComparable k, NiceUnpackedValue v+ )+ => BigMapId k v -> m Natural+getBigMapSize bmId =+ Unsafe.fromIntegral @Int @Natural . length <$> getAllBigMapValues bmId++-- | Get the public key associated with given address.+-- Fail if given address is not an implicit account.+getPublicKey :: (HasCallStack, MonadCleveland caps m) => ImplicitAddress -> m PublicKey+getPublicKey addr = do+ withCap getMiscCap \cap -> cmiGetPublicKey cap addr++-- | Get the chain's @ChainId@.+getChainId :: (HasCallStack, MonadCleveland caps m) => m ChainId+getChainId = do+ withCap getMiscCap \cap -> cmiGetChainId cap++-- | Advance at least the given amount of time, or until a new block is baked,+-- whichever happens last.+--+-- On a real network, this is implemented using @threadDelay@, so it's advisable+-- to use small amounts of time only.+advanceTime+ :: forall unit caps m+ . (HasCallStack, MonadCleveland caps m, KnownDivRat unit Second)+ => Time unit -> m ()+advanceTime time = do+ withCap getMiscCap \cap -> cmiAdvanceTime cap time++-- | Wait till the provided number of levels is past.+advanceLevel+ :: forall caps m+ . (HasCallStack, MonadCleveland caps m)+ => Natural -> m ()+advanceLevel l = do+ withCap getMiscCap \cap -> cmiAdvanceToLevel cap (+ l)++-- | Wait till the provided level is reached.+advanceToLevel+ :: forall caps m+ . (HasCallStack, MonadCleveland caps m)+ => Natural -> m ()+advanceToLevel target = do+ withCap getMiscCap \cap -> cmiAdvanceToLevel cap (const target)++-- | Get the timestamp observed by the last block to be baked.+getNow :: (HasCallStack, MonadCleveland caps m) => m Timestamp+getNow = do+ withCap getMiscCap \cap -> cmiGetNow cap++-- | Get the current level observed by the last block to be baked.+getLevel :: (HasCallStack, MonadCleveland caps m) => m Natural+getLevel = do+ withCap getMiscCap \cap -> cmiGetLevel cap++-- | Get approximate block interval in seconds. Note, that this value+-- is minimal bound and real intervals can be larger, see+-- http://tezos.gitlab.io/active/consensus.html#minimal-block-delay-function+-- for more information about block delays.+getApproximateBlockInterval :: (HasCallStack, MonadCleveland caps m) => m (Time Second)+getApproximateBlockInterval = do+ withCap getMiscCap \cap -> cmiGetApproximateBlockInterval cap++-- | Get minimal block delay in seconds. This is essentially the same as+-- 'getApproximateBlockInterval', but returns a 'Natural' instead of @Time+-- Second@.+--+-- Can be useful when testing code using @MIN_BLOCK_TIME@ instruction.+getMinBlockTime :: (HasCallStack, MonadCleveland caps m) => m Natural+getMinBlockTime = toNum @Second <$> getApproximateBlockInterval++-- | Execute a contract's code without originating it.+-- The chain's state will not be modified.+--+-- Notes:+--+-- * If the contract's code emits operations, they will not be executed.+-- * The sender's account won't be debited.+-- * When running an _originated_ contract, the @BALANCE@ instruction returns the+-- sum of the contract's balance before the transfer operation + the amount of tz being transferred.+-- In other words, this invariant holds: @BALANCE >= AMOUNT@.+-- However, since `runCode` allows overriding the @BALANCE@ instruction,+-- then this invariant no longer holds. It's possible that @BALANCE < AMOUNT@.+runCode+ :: (HasCallStack, MonadCleveland caps m, HasRPCRepr st, IsoValue (AsRPC st))+ => RunCode cp st vd -> m (AsRPC st)+runCode rc = do+ sender <- view senderL+ withCap getMiscCap \cap -> cmiRunCode cap sender rc++-- | Execute multiple testing scenarios independently.+--+-- * Actions performed before 'branchout' will be observed by all branches.+-- * Actions performed in branches will _not_ be observed by any actions performed after 'branchout'.+-- * Actions performed in one branch will _not_ be observed by another branch.+-- * The test succeeds IFF all branches succeed.+-- * If any branch fails, the test ends immediately and the remaining branches+-- won't be executed.+--+-- The following property holds:+--+-- > pre >> branchout [a, b, c] = branchout [pre >> a, pre >> b, pre >> c]+--+-- The list of branches must be non-empty.+branchout :: forall caps m. (MonadEmulated caps m) => [(Text, m ())] -> m ()+branchout branches = do+ caps <- ask+ let branches' :: [(Text, ClevelandBaseMonad caps ())] = second (flip runReaderT caps) <$> branches+ lift $ eiBranchout (getEmulatedCap caps) branches'++-- | Execute one or more actions and roll them back afterwards.+-- Actions performed in 'offshoot' will _not_ be observed by any+-- actions performed after 'offshoot'.+--+-- Similar to 'branchout', but accepts one single branch.+offshoot :: forall caps m. MonadEmulated caps m => Text -> m () -> m ()+offshoot branchName branch = branchout [(branchName, branch)]++{- | Returns the result of the action with the logs it produced. Logs are messages+printed by the Lorentz instruction 'Lorentz.printComment'.++This function can be combined either with lens-based accessors or helper functions to get+more specific information about logs.++Examples:++@+(logsInfo, _) <- getMorleyLogs scenario+logsInfo ^.. each . logsL @== [MorleyLogs ["log"], MorleyLogs ["log2"]]+logsInfo ^.. each . filterLogsByAddrL addr @== [MorleyLogs ["log"]]+@++@+(logsInfo, _) <- getMorleyLogs scenario+collectLogs logsInfo @== MorleyLogs ["log", "log2"]+logsForAddress logsInfo @== [MorleyLogs ["log"]]+@++-}+getMorleyLogs :: forall a caps m. MonadEmulated caps m => m a -> m (LogsInfo, a)+getMorleyLogs action = do+ caps <- ask+ let action' :: ClevelandBaseMonad caps a = runReaderT action caps+ lift $ eiGetMorleyLogs (getEmulatedCap caps) action'++-- | Version of `getMorleyLogs` for actions that don't return a result.+getMorleyLogs_ :: MonadEmulated caps m => m () -> m LogsInfo+getMorleyLogs_ action = fst <$> getMorleyLogs action++-- | Updates voting power accessible via @VOTING_POWER@ and similar+-- instructions.+setVotingPowers :: MonadEmulated caps m => VotingPowers -> m ()+setVotingPowers vp = do+ withCap getEmulatedCap \cap -> eiSetVotingPowers cap vp++-- | A helper constraint synonym to make signatures below a bit shorter+type EqBaseMonad a b = ClevelandBaseMonad a ~ ClevelandBaseMonad b++-- | Perform an action if we are currently in emulation mode.+-- See also 'ifEmulation' note on constraints.+whenEmulation+ :: MonadCleveland caps m+ => (forall caps1 m1. (EqBaseMonad caps caps1, MonadEmulated caps1 m1) => m1 ())+ -> m ()+whenEmulation action = ifEmulation action pass++-- | Perform an action if we are currently in network mode.+-- See also 'ifEmulation' note on constraints.+whenNetwork+ :: MonadCleveland caps m+ => (forall caps1 m1. (EqBaseMonad caps caps1, MonadNetwork caps1 m1) => m1 ())+ -> m ()+whenNetwork action = ifEmulation pass action++{- | Perform one action if we are currently in emulation mode, another otherwise++Functions passed as the first two arguments are universally quantified over+the outer monad, so if additional constraints are required beyond+'MonadEmulated' or 'MonadCleveland', those constraints have to go on the base+monad, e.g.++@+someFunction :: (MonadCleveland caps m, MonadFail (ClevelandBaseMonad caps)) => m ()+someFunction = whenEmulation do+ Just x <- pure (Just 1 :: Maybe Int) -- this would error without MonadFail+ runIO $ print x+@+-}+ifEmulation+ :: forall a caps m+ . MonadCleveland caps m+ => (forall caps1 m1. (EqBaseMonad caps caps1, MonadEmulated caps1 m1) => m1 a)+ -> (forall caps1 m1. (EqBaseMonad caps caps1, MonadNetwork caps1 m1) => m1 a)+ -> m a+ifEmulation onEmu onNet = withCap getMiscCap cmiUnderlyingImpl >>= \case+ Right impl -> withCap (view clevelandCapsL) (runReaderT onNet . NetworkCaps impl)+ Left impl -> withCap (view clevelandCapsL) (runReaderT onEmu . EmulatedCaps impl)++-- | Get a 'MorleyClientEnv' when running a test on network. Useful to run+-- f.ex. @tezos-client@ inside a network test.+--+-- This is considered a pretty low-level function, so it's better to avoid it in+-- most cases.+getMorleyClientEnv :: MonadNetwork caps m => m MorleyClientEnv+getMorleyClientEnv = asks (neMorleyClientEnv . getNetworkEnvCap)
+ src/Test/Cleveland/Internal/Actions/MonadOps.hs view
@@ -0,0 +1,38 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++-- | Internally used typeclass for operations-related actions+module Test.Cleveland.Internal.Actions.MonadOps+ ( module Test.Cleveland.Internal.Actions.MonadOps+ ) where++import Test.Cleveland.Internal.Abstract++-- | Typeclass for monads where operations-related actions can occur.+--+-- This is implemented for 'MonadCleveland' and batch context.+--+-- Has 'Functor' as a superclass constraint for convenience, all the related methods+-- require it.+--+-- This is used internally to implement @originate@ and @transfer@. There is a+-- more specific, more user-friendly @MonadOps@ class defined in+-- "Test.Cleveland.Internal.Actions".+class Functor m => MonadOpsInternal m where+ -- | Obtain 'ClevelandOpsImpl' suitable for the current \"monad\".+ --+ -- In CPS style, because the \"monad\" can be actually not a monad, so+ -- it can't work like 'ask' for 'ReaderT'.+ withOpsCap :: (ClevelandOpsImpl m -> m a) -> m a++instance MonadOpsInternal ClevelandOpsBatch where+ withOpsCap mkAction = mkAction batchedOpsImpl++instance (HasClevelandCaps caps, ClevelandBaseMonad caps ~ m) => MonadOpsInternal (ReaderT caps m) where+ withOpsCap mkAction = do+ opsCap :: ClevelandOpsImpl m <- asks getOpsCap+ let opsCap' :: ClevelandOpsImpl (ReaderT caps m) =+ ClevelandOpsImpl+ { coiRunOperationBatch = lift ... coiRunOperationBatch opsCap+ }+ mkAction opsCap'
+ src/Test/Cleveland/Internal/Actions/Originate.hs view
@@ -0,0 +1,225 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++-- | Machinery for the variadic 'originate' function.+module Test.Cleveland.Internal.Actions.Originate+ ( module Test.Cleveland.Internal.Actions.Originate+ ) where++import Lorentz+ (Contract(..), NiceParameter, NiceStorage, NiceViewsDescriptor, niceStorageEvi,+ toMichelsonContract)++import Data.Constraint ((\\))+import GHC.TypeLits (ErrorMessage(..), TypeError)++import Morley.Client.Types+import Morley.Michelson.Typed (convertContract, toVal, untypeValue)+import Morley.Michelson.Typed qualified as T+import Morley.Michelson.Untyped qualified as U+import Morley.Tezos.Address+import Morley.Tezos.Core+import Test.Cleveland.Internal.Abstract+import Test.Cleveland.Internal.Actions.Helpers+import Test.Cleveland.Internal.Actions.MonadOps++-- | Originate a new contract with given data.+--+-- Can accept untypted or Lorentz contracts as-is. With typed Michelson contracts,+-- you need to wrap the contract in 'TypedContract' specifying its Haskell-land+-- parameter, storage types and view descriptors, e.g.+--+-- > originate "typed contract" defaultStorage $ TypedContract @Param @Storage @() michelsonContract+--+-- Storage type can be auto-deduced in most cases, so you can skip it with @\@_@.+--+-- After the mandatory arguments, you can add 'Large' or a 'Mutez' value, e.g.+-- by using @tz@ quasi-quoter:+--+-- > originate "contract" initialStorage contract Large+-- > originate "contract" initialStorage contract [tz|123micro|]+-- > originate "contract" initialStorage contract [tz|123micro|] Large+--+-- The order is arbitrary, but each can be specified at most once.+originate :: forall contract r. (HasCallStack, OriginateFunc contract 'NoBalance 'NotLarge r)+ => ContractAlias -> ContractStorage contract -> contract -> r+originate = originate'r @contract @'NoBalance @'NotLarge ... initialData @contract++----------------------------------------------------------------------------+-- Main origination implementations+----------------------------------------------------------------------------++-- | Class implementing actual origination.+class Originator od res where+ -- | Low-level polymorphic origination function.+ -- It takes 'UntypedOriginateData', 'TypedOriginateData' or 'OriginateData',+ -- and returns correspondingly an 'Address', or a 'ContractHandle', in a+ -- suitable monad.+ originateFn :: HasCallStack => od -> res++instance (a ~ ContractHandle cp st vd, MonadOpsInternal m+ , Originator (UntypedOriginateData large) (m ContractAddress))+ => Originator (OriginateData cp st vd large) (m a) where+ originateFn od@OriginateData{ odContract=Contract{}, ..} = do+ let uod = UntypedOriginateData @large+ odName+ odBalance+ (untypeValue (toVal odStorage) \\ niceStorageEvi @st)+ (convertContract $ toMichelsonContract (odContract od))+ ContractHandle odName <$> originateFn uod++instance (a ~ ContractHandle cp st vd, MonadOpsInternal m+ , Originator (UntypedOriginateData large) (m ContractAddress)+ , NiceStorage st, NiceViewsDescriptor vd, NiceParameter cp)+ => Originator (TypedOriginateData cp st vd large) (m a) where+ originateFn tod@TypedOriginateData{todContract = T.Contract{}, ..} = do+ let uod = UntypedOriginateData @large+ todName+ todBalance+ (untypeValue (toVal todStorage))+ (convertContract (todContract tod))+ ContractHandle todName <$> originateFn uod++instance (a ~ ContractAddress, MonadOpsInternal m)+ => Originator (UntypedOriginateData 'NotLarge) (m a) where+ originateFn uod = withOpsCap \opsCap ->+ runSingleOperation opsCap "origination" (OpOriginate uod) \case+ OpOriginate addr -> Just addr+ _ -> Nothing++instance (HasClevelandCaps caps, base ~ ClevelandBaseMonad caps, a ~ ContractAddress) =>+ Originator (UntypedOriginateData 'IsLarge) (ReaderT caps base a) where+ originateFn uod = do+ sender <- view senderL+ withCap getMiscCap \cap -> cmiOriginateLargeUntyped cap sender uod++----------------------------------------------------------------------------+-- ContractClass+----------------------------------------------------------------------------++-- | Type class that abstracts different contract types for the purpose of+-- origination.+class ContractClass contract where+ type ContractStorage contract+ type ContractOriginateData contract :: LargeOrigination -> Type+ initialData+ :: ContractAlias -> ContractStorage contract -> contract+ -> ContractOriginateData contract 'NotLarge++instance ContractClass (Contract cp st vd) where+ type ContractStorage (Contract cp st vd) = st+ type ContractOriginateData (Contract cp st vd) = OriginateData cp st vd+ initialData = flip OriginateData zeroMutez++instance ContractClass U.Contract where+ type ContractStorage U.Contract = U.Value+ type ContractOriginateData U.Contract = UntypedOriginateData+ initialData = flip UntypedOriginateData zeroMutez++instance ContractClass (TypedContract cp st vd) where+ type ContractStorage (TypedContract cp st vd) = st+ type ContractOriginateData (TypedContract cp st vd) = TypedOriginateData cp st vd+ initialData name store (TypedContract contract) =+ TypedOriginateData+ { todName = name+ , todBalance = zeroMutez+ , todStorage = store+ , todContract = contract+ }++----------------------------------------------------------------------------+-- "The printf trick"+----------------------------------------------------------------------------++-- | The class implementing a guarded "printf trick" for the 'originate' function.+--+-- If you see GHC asking for this constraint, you most likely need to add+-- 'MonadOriginate' constraint on the return monad instead.+class ContractClass contract => OriginateFunc contract (bal :: HasBalance) isLarge r where+ originate'r :: HasCallStack => ContractOriginateData contract isLarge -> r+ default originate'r+ :: (HasCallStack, Originator (ContractOriginateData contract isLarge) r)+ => ContractOriginateData contract isLarge -> r+ originate'r = originateFn++-- | Simple flag to track duplicate balance specification.+data HasBalance = NoBalance | HasBalance++-- | Type family raising a type error on 'HasBalance' argument. Used to improve+-- error reporting for 'OriginateFunc' instances with equality constraints.+type family CheckDupBalance mod :: Constraint where+ CheckDupBalance 'HasBalance = TypeError ('Text "Balance is specified more than once.")+ CheckDupBalance 'NoBalance = ()++instance+ ( ModifyOriginationData (ContractOriginateData ct)+ , OriginateFunc ct 'HasBalance isLarge r+ , CheckDupBalance bal, bal ~ 'NoBalance)+ => OriginateFunc ct bal isLarge (Mutez -> r) where+ originate'r initData x = originate'r @ct @'HasBalance $ setBalance x initData++-- | Type family raising a type error on 'IsLarge' argument. Used to improve+-- error reporting for 'OriginateFunc' instances with equality constraints.+type family CheckDupLarge mod :: Constraint where+ CheckDupLarge 'IsLarge = TypeError ('Text "Large is specified more than once.")+ CheckDupLarge 'NotLarge = ()++instance (ModifyOriginationData (ContractOriginateData ct)+ , OriginateFunc ct bal 'IsLarge r+ , CheckDupLarge isLarge, isLarge ~ 'NotLarge)+ => OriginateFunc ct bal isLarge (Large -> r) where+ originate'r initData Large = originate'r @ct @bal $ setLarge initData++-- | Convenience synonym.+type OFConstraint ct large r =+ ( ContractClass ct, Originator (ContractOriginateData ct large) r)++-- | The terminating case for batched transfer.+instance OFConstraint ct large (ClevelandOpsBatch a)+ => OriginateFunc ct bal large (ClevelandOpsBatch a)++-- | The terminating case for Cleveland monads.+instance OFConstraint ct large (ReaderT cap base a)+ => OriginateFunc ct bal large (ReaderT cap base a)++-- | A convenient synonym class to require the terminating instance for a given+-- monad without leaking too much implementation detail.+class (forall ct bal large a. OFConstraint ct large (m a) => OriginateFunc ct bal large (m a))+ => MonadOriginate m+instance (forall ct bal large a. OFConstraint ct large (m a) => OriginateFunc ct bal large (m a))+ => MonadOriginate m++-- | Catchall incoherent instance to report argument errors.+instance {-# INCOHERENT #-}+ ( ContractClass ct+ , TypeError ('Text "Incorrect argument for the 'originate' function: " ':<>: 'ShowType x ':$$:+ 'Text "If in doubt, try adding a type annotation."))+ => OriginateFunc ct bal large (x -> r) where+ originate'r = error "impossible"++----------------------------------------------------------------------------+-- Applying modifiers to the initial data+----------------------------------------------------------------------------++-- | Mark a contract that doesn't fit into the origination size limit.+-- This will execute multiple origination steps.+--+-- Such origination cannot be batched (it simply may not fit).+data Large = Large++-- | Type class implementing modifications to origination data.+class ModifyOriginationData od where+ setBalance :: Mutez -> od large -> od large+ setLarge :: od 'NotLarge -> od 'IsLarge++instance ModifyOriginationData (OriginateData cp st vd) where+ setBalance bal od = od {odBalance = bal}+ setLarge OriginateData{..} = OriginateData{..}++instance ModifyOriginationData (UntypedOriginateData) where+ setBalance bal od = od {uodBalance = bal}+ setLarge UntypedOriginateData{..} = UntypedOriginateData{..}++instance ModifyOriginationData (TypedOriginateData cp st vd) where+ setBalance bal od = od {todBalance = bal}+ setLarge TypedOriginateData{..} = TypedOriginateData{..}
+ src/Test/Cleveland/Internal/Actions/Transfer.hs view
@@ -0,0 +1,331 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++-- | Machinery for the variadic 'transfer' function.+module Test.Cleveland.Internal.Actions.Transfer+ ( module Test.Cleveland.Internal.Actions.Transfer+ ) where++import Data.Singletons.TH (SingI(..), genSingletons)+import GHC.TypeLits (ErrorMessage(..), TypeError)++import Lorentz+import Morley.Client.Types+import Morley.Michelson.Typed (Dict(..))+import Morley.Michelson.Untyped qualified as U+import Morley.Tezos.Address+import Test.Cleveland.Internal.Abstract+import Test.Cleveland.Internal.Actions.MonadOps+import Test.Cleveland.Lorentz.Types++----------------------------------------------------------------------------+-- TransferResult and its singletons+----------------------------------------------------------------------------++-- | Simple flag to track whether we want to return list of emitted events.+data TransferResult = TransferIgnoreResult | TransferWithEmits++-- | Type family encoding the actual 'transfer' result depending on+-- 'TransferResult'+type family FTransferResult emit :: Type where+ FTransferResult 'TransferWithEmits = [ContractEvent]+ FTransferResult 'TransferIgnoreResult = ()++genSingletons [''TransferResult]++{-+Note [TransferResult singletons]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~++If you're wondering why this complicated song and dance with singletons and not+just multiple terminating instances for each 'TransferWithEmits' value, if we+want to keep 'MonadTransfer', we need terminating instances work for any @emit@,+possibly constrained; if we have instances for a specific value, it's ambiguous+which one to choose in 'MonadTransfer'.++They're declared at the top of the file because of TH staging rules.++-- @lierdakil+-}++----------------------------------------------------------------------------+-- transfer+----------------------------------------------------------------------------++-- | Base method for making a transfer.+--+-- You can specify additional arguments after the destination address to modify+-- optional transfer arguments. Those can either be 'Mutez' to specify transfer+-- amount (0 by default), or a specially constructed call descriptor. The order+-- is arbitrary, but it is usually more convenient to specify transfer amount+-- first. For example:+--+-- > transfer addr [tz|123u|] $ calling (ep @"Entrypoint") ()+-- > transfer addr [tz|123u|]+--+-- If the call isn't specified, then the default entrypoint will be called with+-- @()@, i.e.+--+-- > transfer addr+--+-- is functionally the same as+--+-- > transfer addr $ calling def ()+--+-- If the address in the first argument is untyped, the transfer is unchecked.+-- Unchecked transfers must use 'unsafeCalling' for the call specification. You+-- can also use 'unsafeCalling' with typed address to force an unchecked+-- transfer.+--+-- See "Test.Cleveland.Internal.Actions.Transfer" for further explanation of the+-- interface.+--+-- By default, the sender is the account associated with the @moneybag@ alias.+-- This can be overridden with the @--cleveland-moneybag-alias@ command line+-- option, the @TASTY_CLEVELAND_MONEYBAG_ALIAS@ env var, or @withSender@.+transfer :: forall addr r.+ ( HasCallStack+ , TransferFunc ('Incomplete (InitialTransferMode addr))+ 'TransferIgnoreResult 'HasNoAmount r+ , ToL1Address addr )+ => addr -> r+transfer = transfer'r @_ @'TransferIgnoreResult @'HasNoAmount . initialData @addr++----------------------------------------------------------------------------+-- Initial transfer data and wrappers+----------------------------------------------------------------------------++-- | Data-kind for tracking what type of call we're making.+data TransferMode = Checked Type | Unchecked | Incomplete TransferMode++-- | Data-kind for call specification.+data GenericCall mode where+ CheckedCall+ :: (NiceParameter epArg, HasEntrypointArg param epRef epArg)+ => epRef -> epArg -> GenericCall ('Checked param)+ UncheckedCall :: NiceParameter epArg => U.EpName -> epArg -> GenericCall 'Unchecked+ UnspecifiedCall :: GenericCall ('Incomplete param)++-- | Generic version of 'TransferData'+data GenericTransferData mode =+ GenericTransferData+ { gtdAddr :: L1Address+ , gtdCall :: GenericCall mode+ , gtdAmount :: Mutez+ }++-- | Choose the initial 'TransferMode' based on the type of destination address.+type family InitialTransferMode addr :: TransferMode where+ InitialTransferMode ContractAddress = 'Unchecked+ InitialTransferMode ImplicitAddress = 'Unchecked+ InitialTransferMode L1Address = 'Unchecked+ InitialTransferMode (L1TAddress param _) = 'Checked param+ InitialTransferMode (ContractHandle param _ _) = 'Checked param++-- | Construct initial 'GenericTransferData' for a given address.+initialData+ :: ToL1Address addr+ => addr -> GenericTransferData ('Incomplete (InitialTransferMode addr))+initialData addr = GenericTransferData+ { gtdAddr = toL1Address addr+ , gtdAmount = zeroMutez+ , gtdCall = UnspecifiedCall+ }++----------------------------------------------------------------------------+-- "The printf trick" for transfer+----------------------------------------------------------------------------++-- | Simple flag to track duplicate amount specification.+data HasAmount = HasAmount | HasNoAmount++-- | The class implementing a guarded "printf trick" for the 'transfer' function.+--+-- If you see GHC asking for this constraint, you most likely need to add+-- 'MonadTransfer' constraint on the return monad instead.+class TransferFunc (mode :: TransferMode) (emit :: TransferResult) (hasAmount :: HasAmount) r where+ transfer'r :: HasCallStack => GenericTransferData mode -> r++-- | Type family raising a type error on 'HasAmount' argument. Used to improve+-- error reporting for 'TransferFunc' instances with equality constraints.+type family NoDuplicateAmount am :: Constraint where+ NoDuplicateAmount 'HasAmount = TypeError ('Text "Amount is specified more than once.")+ NoDuplicateAmount 'HasNoAmount = ()++instance (TransferFunc mode emit 'HasAmount r, NoDuplicateAmount am, am ~ 'HasNoAmount)+ => TransferFunc mode emit am (Mutez -> r) where+ transfer'r initData x = transfer'r @_ @emit @'HasAmount initData{gtdAmount = x}++-- | Type family raising a type error on 'TransferWithEmits' argument. Used to+-- improve error reporting for 'TransferFunc' instances with equality+-- constraints.+type family NoDuplicateEmit am :: Constraint where+ NoDuplicateEmit 'TransferWithEmits =+ TypeError ('Text "WithContractEvents is specified more than once.")+ NoDuplicateEmit 'TransferIgnoreResult = ()++instance (TransferFunc mode 'TransferWithEmits am r+ , NoDuplicateEmit emit, emit ~ 'TransferIgnoreResult)+ => TransferFunc mode emit am (WithContractEvents -> r) where+ transfer'r initData _ = transfer'r @_ @'TransferWithEmits @am initData++-- | Type family that defines possible mode conversions in 'TransferFunc'.+-- Basically, we don't allow unchecked calls to become checked, and we require+-- that checked calls do not change the parameter type mid-way.+type family MatchModes from to :: Constraint where+ MatchModes ('Incomplete _) 'Unchecked = ()+ MatchModes ('Incomplete ('Checked param1)) ('Checked param2) = param1 ~ param2+ MatchModes ('Incomplete 'Unchecked) _ = TypeError (+ 'Text "Can not use this type of call with an untyped address."+ ':$$: 'Text "Try using 'unsafeCalling' instead."+ )+ MatchModes _ _ = TypeError ('Text "Call is specified more than once.")++instance (TransferFunc modeTo emit am r, MatchModes modeFrom modeTo)+ => TransferFunc modeFrom emit am (GenericCall modeTo -> r) where+ transfer'r GenericTransferData{..} x =+ transfer'r @_ @emit @am $ GenericTransferData{gtdCall = x, ..}++-- | The terminating case for batched transfer+instance ( SingI emit, DoTransfer mode, a ~ FTransferResult emit)+ => TransferFunc mode emit am (ClevelandOpsBatch a) where+ transfer'r = case sing @emit of+ STransferWithEmits -> doTransfer+ STransferIgnoreResult -> void . doTransfer++-- | The terminating case for Cleveland monads+instance ( SingI emit, DoTransfer mode, HasClevelandCaps cap+ , base ~ ClevelandBaseMonad cap, a ~ FTransferResult emit )+ => TransferFunc mode emit am (ReaderT cap base a) where+ transfer'r = case sing @emit of+ STransferWithEmits -> doTransfer+ STransferIgnoreResult -> void . doTransfer++-- | A convenient synonym class to require the terminating instance for a given+-- monad without leaking too much implementation detail.+class (+ forall mod am emit a. (SingI emit, DoTransfer mod, a ~ FTransferResult emit)+ => TransferFunc mod emit am (m a)+ ) => MonadTransfer m+instance (+ forall mod am emit a. (SingI emit, DoTransfer mod, a ~ FTransferResult emit)+ => TransferFunc mod emit am (m a)+ ) => MonadTransfer m++-- | Catchall incoherent instance to report argument errors.+instance {-# INCOHERENT #-}+ TypeError ('Text "Incorrect argument for the 'transfer' function: " ':<>: 'ShowType x ':$$:+ 'Text "If in doubt, try adding a type annotation.")+ => TransferFunc mode emit am (x -> r) where+ transfer'r = error "impossible"++----------------------------------------------------------------------------+-- Making the actual transfer+----------------------------------------------------------------------------++-- | Typeclass abstracting making the actual transfer.+class DoTransfer mode where+ doTransfer :: (HasCallStack, MonadOpsInternal m) => GenericTransferData mode -> m [ContractEvent]++-- | Make the transfer given 'TransferData'+runTransfer :: (HasCallStack, MonadOpsInternal m) => TransferData -> m [ContractEvent]+runTransfer td = withOpsCap \opsCap ->+ runSingleOperation opsCap "transfer" (OpTransfer td) \case+ OpTransfer ops -> Just ops+ _ -> Nothing++instance DoTransfer 'Unchecked where+ doTransfer GenericTransferData+ { gtdAddr = tdTo+ , gtdAmount = tdAmount+ , gtdCall = UncheckedCall tdEntrypoint tdParameter+ } = runTransfer TransferData{..}++instance DoTransfer ('Checked param) where+ doTransfer GenericTransferData+ { gtdAddr = tdTo+ , gtdAmount = tdAmount+ , gtdCall = CheckedCall (epRef :: epRef) (tdParameter :: epArg)+ } | (Dict, tdEntrypoint) <- useHasEntrypointArg @param @epRef @epArg epRef+ = runTransfer TransferData{..}++instance HasEntrypointArg param (EntrypointRef 'Nothing) ()+ => DoTransfer ('Incomplete ('Checked param)) where+ doTransfer GenericTransferData{..} =+ doTransfer GenericTransferData {gtdCall = calling CallDefault @_ @param (), ..}++instance DoTransfer ('Incomplete 'Unchecked) where+ doTransfer GenericTransferData{..} =+ doTransfer GenericTransferData {gtdCall = unsafeCalling U.DefEpName (), ..}++----------------------------------------------------------------------------+-- Call specification+----------------------------------------------------------------------------++-- | Safely call an entrypoint specified by the first argument with the+-- provided parameter.+--+-- The first character of the entrypoint name must be capitalized.+--+-- This is "safe" in the sense that the contract is checked if it indeed has the+-- specified entrypoint and the entrypoint in question accepts the argument+-- provided, a type error is raised otherwise.+--+-- > transfer addr $ calling (ep @"Entrypoint") ()+--+-- Use 'CallDefault' or @def@ to call the default entrypoint.+--+-- > transfer addr $ calling def ()+--+-- Notice that type variables for entrypoint argument and full parameter are+-- specified after the entrypoint. This is done so more for readability. F. ex.:+--+-- > transfer addr $ calling def @Integer 123+--+-- This does also marginally simplify type inference in the case of partial+-- application.+calling+ :: forall mname.+ EntrypointRef mname+ -> forall epArg param. (NiceParameter epArg, HasEntrypointArg param (EntrypointRef mname) epArg)+ => epArg -> GenericCall ('Checked param)+calling arg = CheckedCall arg++-- | Unsafely call an entrypoint specified by the first argument with the+-- provided parameter.+--+-- This is "unsafe" in the sense that there is no check that the contract+-- indeed has the specified entrypoint or that the entrypoint in question+-- accepts the argument provided.+--+-- Also, no compile-time checks are performed on the entrypoint name, so it+-- can be malformed.+--+-- > transfer addr $ unsafeCalling (ep @"Entrypoint") ()+--+-- Overloaded labels are supported with 'unsafeCalling', so you can specify the+-- entrypoint as an overloaded label:+--+-- > transfer addr $ unsafeCalling #entrypoint ()+--+-- Use 'U.DefEpName' or @def@ to call the default entrypoint.+--+-- Notice that the type variable for the entrypoint argument is specified after+-- the entrypoint. This is done so more for readability. F. ex.:+--+-- > transfer addr $ calling def @Integer 123+--+-- This does also marginally simplify type inference in the case of partial+-- application.+unsafeCalling :: U.EpName -> forall epArg. NiceParameter epArg => epArg -> GenericCall 'Unchecked+unsafeCalling arg = UncheckedCall arg++----------------------------------------------------------------------------+-- Return value specification+----------------------------------------------------------------------------++-- | 'transfer' flag to signal we want contract events emitted by @EMIT@+-- returned. Passed in the variadic part of 'transfer', e.g.+--+-- > transfer addr [tz|123u|] WithContractEvents $ calling (ep @"Entrypoint") ()+data WithContractEvents = WithContractEvents
+ src/Test/Cleveland/Internal/Actions/TransferFailurePredicate.hs view
@@ -0,0 +1,137 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++-- | 'TransferFailure' Predicates+module Test.Cleveland.Internal.Actions.TransferFailurePredicate+ ( module Test.Cleveland.Internal.Actions.TransferFailurePredicate+ ) where++import Data.Either.Validation (Validation(..))+import Fmt (Builder, build)++import Lorentz+ (CustomError(..), ErrorTagMap, IsError, Label, MText, MustHaveErrorArg, errorTagToMText,+ errorToVal, errorToValNumeric, toVal)+import Lorentz.Constraints+import Morley.Micheline (Expression, fromExpression, toExpression)+import Morley.Michelson.Printer.Util (buildRenderDoc)+import Morley.Michelson.Typed (SomeConstant, SomeConstrainedValue(..))+import Morley.Michelson.Typed qualified as T+import Test.Cleveland.Internal.Abstract+import Test.Cleveland.Lorentz.Types++-- | A predicate that checks whether a transfer operation failed for the expected reason.+--+-- Predicates can be combined using the '&&' and '||' operators.+data TransferFailurePredicate+ = TransferFailurePredicate+ (TransferFailure -> Validation Builder ())+ -- ^ A predicate that either returns () or, if it fails,+ -- a message explaining what the expected outcome was.+ | AndPredicate (NonEmpty TransferFailurePredicate)+ | OrPredicate (NonEmpty TransferFailurePredicate)++instance Boolean TransferFailurePredicate where+ AndPredicate l && AndPredicate r = AndPredicate $ l <> r+ AndPredicate l && r = AndPredicate $ l <> one r+ l && AndPredicate r = AndPredicate $ one l <> r+ l && r = AndPredicate $ one l <> one r++ OrPredicate l || OrPredicate r = OrPredicate $ l <> r+ OrPredicate l || r = OrPredicate $ l <> one r+ l || OrPredicate r = OrPredicate $ one l <> r+ l || r = OrPredicate $ one l <> one r++transferFailureReasonPredicate+ :: (TransferFailureReason -> Validation Builder ())+ -> TransferFailurePredicate+transferFailureReasonPredicate p = TransferFailurePredicate $+ \(TransferFailure _ reason) -> p reason++-- | Asserts that interpretation of a contract failed due to an overflow error.+shiftOverflow :: TransferFailurePredicate+shiftOverflow = transferFailureReasonPredicate \case+ ShiftOverflow -> pass+ _ -> Failure "Contract failed due to an overflow error"++-- | Asserts that an action failed due to an attempt to transfer 0tz towards a simple address.+emptyTransaction :: TransferFailurePredicate+emptyTransaction = transferFailureReasonPredicate \case+ EmptyTransaction -> pass+ _ -> Failure "Attempted to transfer 0tz to a simple address"++-- | Asserts that an action failed due to an attempt to call a contract with an invalid parameter.+badParameter :: TransferFailurePredicate+badParameter = transferFailureReasonPredicate \case+ BadParameter -> pass+ _ -> Failure "Attempted to call a contract with a parameter of the wrong type"++-- | Asserts that interpretation of a contract failed due to gas exhaustion.+gasExhaustion :: TransferFailurePredicate+gasExhaustion = transferFailureReasonPredicate \case+ GasExhaustion -> pass+ _ -> Failure "Execution failed due to gas exhaustion"++-- | Asserts that interpretation of a contract ended with @FAILWITH@, throwing the given error.+--+-- This function should be used together with one of the "@FAILWITH@ constructors"+-- (e.g. 'constant', 'customError').+failedWith :: SomeConstant -> TransferFailurePredicate+failedWith expectedFailWithVal = transferFailureReasonPredicate \case+ FailedWith (EOTVExpression actualFailWithExpr) _+ | actualFailWithExpr `isEq` expectedFailWithVal -> pass+ FailedWith (EOTVTypedValue actualFailWithVal) _+ | toExpression actualFailWithVal `isEq` expectedFailWithVal -> pass+ _ -> Failure $ "Contract failed with: " <> buildRenderDoc expectedFailWithVal+ where+ isEq :: Expression -> SomeConstant -> Bool+ isEq expr (SomeConstant (v :: T.Value t)) =+ either (const False) (== v) (fromExpression @(T.Value t) expr)++-- | Asserts that the error occurred while interpreting the contract with the given address.+addressIs+ :: ToAddress addr+ => addr -- ^ The expected address.+ -> TransferFailurePredicate+addressIs (toAddress -> expectedAddr) = TransferFailurePredicate \err -> do+ let TransferFailure (AddressAndAlias actualAddr _) _ = err+ when (actualAddr /= expectedAddr) $+ Failure $ "Failure occurred in contract with address: " <> build expectedAddr++----------------------------------------------------------------------------+-- 'FAILWITH' errors+----------------------------------------------------------------------------++-- | A constant michelson value that a contract threw with @FAILWITH@.+constant :: forall err. NiceConstant err => err -> SomeConstant+constant err =+ withDict (niceConstantEvi @err) $+ SomeConstant $ toVal err++-- | A lorentz error.+lerror :: forall err. IsError err => err -> SomeConstant+lerror err = errorToVal err SomeConstant++-- | A custom lorentz error.+customError+ :: forall arg tag. (IsError (CustomError tag), MustHaveErrorArg tag (MText, arg))+ => Label tag -> arg -> SomeConstant+customError tag arg =+ lerror $ CustomError tag (errorTagToMText tag, arg)++-- | A custom lorentz error with a @unit@ argument.+customError_+ :: (IsError (CustomError tag), MustHaveErrorArg tag (MText, ()))+ => Label tag -> SomeConstant+customError_ tag = customError tag ()++-- | A custom lorentz error with no argument.+customErrorNoArg+ :: (IsError (CustomError tag), MustHaveErrorArg tag MText)+ => Label tag -> SomeConstant+customErrorNoArg tag =+ lerror $ CustomError tag (errorTagToMText tag)++-- | A lorentz numeric error.+numericError :: forall err. IsError err => ErrorTagMap -> err -> SomeConstant+numericError tagMap err = errorToValNumeric tagMap err SomeConstant
src/Test/Cleveland/Internal/Client.hs view
@@ -6,7 +6,7 @@ module Test.Cleveland.Internal.Client ( ClientM (..)- , runClevelandT+ , runNetworkT -- * Capability implementations , networkOpsImpl@@ -20,7 +20,6 @@ , MoneybagConfigurationException (..) -- * Environment- , NetworkEnv (..) , mkMorleyOnlyRpcEnvNetwork -- * Lens for 'NetworkEnv'@@ -33,7 +32,7 @@ , InternalNetworkScenarioError(..) ) where -import Control.Lens (_head, each, filtered, makeLensesWith)+import Control.Lens (_head, each, filtered) import Data.Aeson.Text qualified as J import Data.Constraint (withDict, (\\)) import Data.Default (def)@@ -45,53 +44,46 @@ import Time (KnownDivRat, Second, Time, sec, threadDelay, toNum, toUnit) import Unsafe qualified (fromIntegral) -import Lorentz (NicePackedValue, toAddress)+import Lorentz (NicePackedValue) import Lorentz qualified as L import Lorentz.Constraints.Scopes (NiceUnpackedValue, niceParameterEvi)-import Morley.AsRPC (AsRPC, HasRPCRepr(..), MaybeRPC(..), TAsRPC, notesAsRPC, rpcSingIEvi)+import Morley.AsRPC (AsRPC, HasRPCRepr(..), TAsRPC, notesAsRPC, rpcSingIEvi) import Morley.Client (MorleyClientEnv, OperationInfo(..), disableAlphanetWarning, runMorleyClientM) import Morley.Client qualified as Client import Morley.Client.Action (Result) import Morley.Client.Action.Reveal qualified as RevealRPC+import Morley.Client.App (failOnTimeout, retryOnceOnTimeout) import Morley.Client.Init qualified as Client import Morley.Client.Logging (logInfo, logWarning) import Morley.Client.RPC.Error qualified as RPC (ClientRpcError(..), RunCodeErrors(..)) import Morley.Client.RPC.Types (AppliedResult(..), BlockConstants(bcHeader), BlockHeaderNoHash(bhnhLevel, bhnhTimestamp),- BlockId(..), OperationHash, OriginationScript(..),+ BlockId(..), IntOpEvent(..), OriginationScript(..), ProtocolParameters(ProtocolParameters, ppCostPerByte, ppMinimalBlockDelay, ppOriginationSize))+import Morley.Client.TezosClient.Impl as TezosClient (getPublicKey, getSecretKey, importKey) import Morley.Client.TezosClient.Types (tceMbTezosClientDataDirL) import Morley.Client.Util qualified as Client import Morley.Micheline (Expression, MichelinePrimitive(..), StringEncode(..), TezosInt64, TezosMutez(..),- _ExpressionPrim, _ExpressionSeq, fromExpression, mpaArgsL, mpaPrimL)+ _ExpressionPrim, _ExpressionSeq, fromExpression, mpaArgsL, mpaPrimL, toExpression)+import Morley.Michelson.Text (unMText) import Morley.Michelson.TypeCheck (typeCheckContractAndStorage, typeCheckingWith) import Morley.Michelson.Typed (BigMapId, SomeAnnotatedValue(..), SomeContractAndStorage(..), toVal) import Morley.Michelson.Typed qualified as T import Morley.Michelson.Untyped qualified as U-import Morley.Tezos.Address (Address, mkKeyAddress)-import Morley.Tezos.Address.Alias (AddressOrAlias(..))+import Morley.Tezos.Address+import Morley.Tezos.Address.Alias import Morley.Tezos.Core as Tezos (Mutez, Timestamp(..), addMutez, subMutez, timestampFromUTCTime, unsafeAddMutez, unsafeMulMutez, unsafeSubMutez) import Morley.Tezos.Crypto-import Morley.Tezos.Crypto qualified as Crypto import Morley.Util.Exception-import Morley.Util.Lens (postfixLFields) import Morley.Util.Named import Test.Cleveland.Internal.Abstract import Test.Cleveland.Internal.Exceptions (addCallStack)+import Test.Cleveland.Lorentz (toL1Address) import Test.Cleveland.Util (ceilingUnit) -data NetworkEnv = NetworkEnv- { neMorleyClientEnv :: MorleyClientEnv- , neSecretKey :: Maybe Crypto.SecretKey- , neMoneybagAlias :: Alias- , neExplicitDataDir :: Bool- }--makeLensesWith postfixLFields ''NetworkEnv- -- | Construct 'Client.MorleyOnlyRpcEnv' from 'NetworkEnv'. mkMorleyOnlyRpcEnvNetwork :: NetworkEnv@@ -109,8 +101,8 @@ -- | This error designates that necessary preparations for running tests -- are not made. data MoneybagConfigurationException- = NoMoneybagAddress Alias- | TwoMoneybagKeys Alias SecretKey Address+ = NoMoneybagAddress ImplicitAlias+ | TwoMoneybagKeys ImplicitAlias SecretKey ImplicitAddress deriving stock (Generic, Show, Eq) instance Buildable MoneybagConfigurationException where@@ -144,7 +136,7 @@ data ClientState = ClientState { csDefaultAliasCounter :: DefaultAliasCounter- , csRefillableAddresses :: Set Address+ , csRefillableAddresses :: Set ImplicitAddress , csMoneybagAddress :: Moneybag } @@ -154,7 +146,7 @@ deriving newtype (Functor, Applicative, Monad, MonadIO, MonadThrow, MonadCatch, MonadReader (IORef ClientState), MonadFail) -data InternalNetworkScenarioError = TooManyRefillIterations Word Address+data InternalNetworkScenarioError = TooManyRefillIterations Word ImplicitAddress deriving stock (Show) instance Buildable InternalNetworkScenarioError where@@ -164,15 +156,18 @@ instance Exception InternalNetworkScenarioError where displayException = pretty -runClevelandT :: NetworkEnv -> ClevelandT ClientM a -> IO a-runClevelandT env scenario = do+runNetworkT :: NetworkEnv -> NetworkT ClientM a -> IO a+runNetworkT env scenario = do disableAlphanetWarning moneybagAddr <- setupMoneybagAddress env- let caps = ClevelandCaps- { ccSender = Sender $ unMoneybag moneybagAddr- , ccMoneybag = moneybagAddr- , ccMiscCap = networkMiscImpl (neMorleyClientEnv env)- , ccOpsCap = networkOpsImpl (neMorleyClientEnv env)+ let caps = NetworkCaps+ { ncNetworkEnv = env+ , ncClevelandCaps = ClevelandCaps+ { ccSender = Sender $ unMoneybag moneybagAddr+ , ccMoneybag = moneybagAddr+ , ccMiscCap = networkMiscImpl env+ , ccOpsCap = networkOpsImpl (neMorleyClientEnv env)+ } } ist <- newIORef ClientState { csDefaultAliasCounter = DefaultAliasCounter 0@@ -195,21 +190,22 @@ (Nothing, Just addr) -> do unless neExplicitDataDir do ek <- runMorleyClientM setupEnv $- Client.getSecretKey (AddressAlias neMoneybagAlias)+ (retryOnceOnTimeout ... TezosClient.getSecretKey)+ (AddressAlias neMoneybagAlias) void $ runMorleyClientM neMorleyClientEnv $- Client.importKey False neMoneybagAlias ek+ failOnTimeout ... TezosClient.importKey False neMoneybagAlias ek pure addr (Nothing, Nothing) -> throwM $ NoMoneybagAddress neMoneybagAlias (Just ek, Just sa) | mkKeyAddress (toPublic ek) == sa -> do unless neExplicitDataDir $ void $ runMorleyClientM neMorleyClientEnv $- Client.importKey False neMoneybagAlias ek+ failOnTimeout ... TezosClient.importKey False neMoneybagAlias ek pure sa | otherwise -> throwM $ TwoMoneybagKeys neMoneybagAlias ek sa (Just ek, Nothing) -> do runMorleyClientM neMorleyClientEnv $- Client.importKey False neMoneybagAlias ek+ failOnTimeout ... TezosClient.importKey False neMoneybagAlias ek return $ mkKeyAddress (toPublic ek) -- | Implementation that works with real network and uses @tezos-node@@@ -221,54 +217,57 @@ { coiRunOperationBatch = runOperationBatch env sender } -networkMiscImpl :: MorleyClientEnv -> ClevelandMiscImpl ClientM-networkMiscImpl env = mapClevelandMiscImplExceptions (addCallStack . exceptionHandler)- ClevelandMiscImpl+networkMiscImpl :: NetworkEnv -> ClevelandMiscImpl ClientM+networkMiscImpl env@NetworkEnv{..} =+ mapClevelandMiscImplExceptions (addCallStack . exceptionHandler) ClevelandMiscImpl { cmiRunIO = liftIO - , cmiOriginateLargeUntyped = \sender untypedOriginateData -> do- (_, res) <- runClientOrigination env- sender Client.originateLargeUntypedContract untypedOriginateData- comment $- "Originated large smart contract " +| uodName untypedOriginateData |+- " with address " <> pretty res+ , cmiOriginateLargeUntyped = \(Sender sender) UntypedOriginateData{..} -> do+ let originationScenario =+ Client.originateLargeUntypedContract True uodName (AddressResolved sender)+ uodBalance uodContract uodStorage Nothing+ -- Note that tezos key reveal operation cost an additional fee+ -- so that's why we reveal keys in origination and transaction+ -- rather than doing it before scenario execution+ (_, res) <- liftIO $ do+ revealKeyUnlessRevealed neMorleyClientEnv sender+ runMorleyClientM neMorleyClientEnv originationScenario+ comment $ "Originated large smart contract " +| uodName |+ " with address " <> pretty res pure res - , cmiSignBytes = \hash signer -> liftIO $ runMorleyClientM env $+ , cmiSignBytes = \hash signer -> liftIO $ runMorleyClientM neMorleyClientEnv $ -- We don't use password protected accounts in cleveland tests Client.signBytes (AddressResolved signer) Nothing hash , cmiGenKey = \sodAlias -> do alias <- resolveSpecificOrDefaultAlias sodAlias- liftIO $ runMorleyClientM env $ Client.genKey alias+ liftIO $ runMorleyClientM neMorleyClientEnv $ Client.genKey alias , cmiGenFreshKey = \sodAlias -> do alias <- resolveSpecificOrDefaultAlias sodAlias- liftIO $ runMorleyClientM env $ Client.genFreshKey alias+ liftIO $ runMorleyClientM neMorleyClientEnv $ Client.genFreshKey alias - , cmiGetBalance = getBalanceHelper- , cmiGetChainId = liftIO $ runMorleyClientM env Client.getChainId+ , cmiGetBalance = \(MkConstrainedAddress a) -> getBalanceHelper a+ , cmiGetChainId = liftIO $ runMorleyClientM neMorleyClientEnv Client.getChainId , cmiAttempt = try , cmiThrow = throwM , cmiMarkAddressRefillable = setAddressRefillable- , cmiRegisterDelegate = \addr -> liftIO $ runMorleyClientM env $ do+ , cmiRegisterDelegate = \addr -> liftIO $ runMorleyClientM neMorleyClientEnv $ do alias <- Client.getAlias (AddressResolved addr) Client.registerDelegate alias Nothing , cmiComment = comment- , cmiEmulatedImpl = pure Nothing+ , cmiUnderlyingImpl = pure $ Right env+ , cmiFailure = clientFailure , .. } where- cmiFailure :: Builder -> ClientM a- cmiFailure = throwM . CustomTestError . pretty- cmiGetBigMapValueMaybe :: (NicePackedValue k, NiceUnpackedValue v) => BigMapId k v -> k -> ClientM (Maybe v) cmiGetBigMapValueMaybe bigMapId k =- liftIO . runMorleyClientM env $ Client.readBigMapValueMaybe bigMapId k+ liftIO . runMorleyClientM neMorleyClientEnv $ Client.readBigMapValueMaybe bigMapId k cmiGetAllBigMapValuesMaybe :: (NiceUnpackedValue v) => BigMapId k v -> ClientM (Maybe [v]) cmiGetAllBigMapValuesMaybe bigMapId =- liftIO . runMorleyClientM env $ Client.readAllBigMapValuesMaybe bigMapId+ liftIO . runMorleyClientM neMorleyClientEnv $ Client.readAllBigMapValuesMaybe bigMapId getStorageType :: Expression -> ClientM U.Ty getStorageType contractExpr = do@@ -282,14 +281,14 @@ . _head case storageTypeExprMb of- Nothing -> cmiFailure $ unlinesF+ Nothing -> clientFailure $ unlinesF [ "Contract expression did not contain a 'storage' expression." , "Contract expression:" , indentF 2 $ build (J.encodeToTextBuilder contractExpr) ] Just storageTypeExpr -> case fromExpression @U.Ty storageTypeExpr of- Left err -> cmiFailure $ unlinesF+ Left err -> clientFailure $ unlinesF [ "'storage' expression was not a valid type expression." , "Storage expression:" , indentF 2 $ build (J.encodeToTextBuilder storageTypeExpr)@@ -298,9 +297,10 @@ ] Right storageType -> pure storageType - cmiGetSomeStorage :: Address -> ClientM SomeAnnotatedValue+ cmiGetSomeStorage :: ContractAddress -> ClientM SomeAnnotatedValue cmiGetSomeStorage addr = do- OriginationScript {osCode, osStorage} <- liftIO . runMorleyClientM env $ Client.getContractScript addr+ OriginationScript {osCode, osStorage} <-+ liftIO . runMorleyClientM neMorleyClientEnv $ Client.getContractScript addr storageType <- getStorageType osCode T.withUType storageType \(storageNotes :: T.Notes t) -> do withDict (rpcSingIEvi @t) do@@ -308,7 +308,7 @@ Right storageValueRPC -> pure $ SomeAnnotatedValue (notesAsRPC storageNotes) storageValueRPC Left err ->- cmiFailure $ unlinesF+ clientFailure $ unlinesF [ "Failed to decode storage expression." , "Storage expression:" , indentF 2 $ build (J.encodeToTextBuilder osStorage)@@ -316,27 +316,30 @@ , indentF 2 $ build err ] - cmiResolveAddress :: Alias -> ClientM Address- cmiResolveAddress = liftIO . runMorleyClientM env . Client.resolveAddress . AddressAlias+ cmiResolveAddress :: Alias kind -> ClientM (KindedAddress kind)+ cmiResolveAddress =+ liftIO . runMorleyClientM neMorleyClientEnv . Client.resolveAddress . AddressAlias - cmiGetPublicKey :: Address -> ClientM PublicKey- cmiGetPublicKey = liftIO . runMorleyClientM env . Client.getPublicKey . AddressResolved+ cmiGetPublicKey :: ImplicitAddress -> ClientM PublicKey+ cmiGetPublicKey = liftIO . runMorleyClientM neMorleyClientEnv .+ (retryOnceOnTimeout ... TezosClient.getPublicKey) . AddressResolved - getBalanceHelper :: Address -> ClientM Mutez- getBalanceHelper = liftIO . runMorleyClientM env . Client.getBalance+ getBalanceHelper :: L1AddressKind kind => KindedAddress kind -> ClientM Mutez+ getBalanceHelper = liftIO . runMorleyClientM neMorleyClientEnv . Client.getBalance - cmiGetDelegate :: Address -> ClientM (Maybe KeyHash)- cmiGetDelegate = liftIO . runMorleyClientM env . Client.getDelegate+ cmiGetDelegate :: ContractAddress -> ClientM (Maybe KeyHash)+ cmiGetDelegate =+ liftIO . runMorleyClientM neMorleyClientEnv . Client.getDelegate cmiGetNow :: ClientM Tezos.Timestamp- cmiGetNow = timestampFromUTCTime <$> getLastBlockTimestamp env+ cmiGetNow = timestampFromUTCTime <$> getLastBlockTimestamp neMorleyClientEnv cmiGetLevel :: ClientM Natural- cmiGetLevel = getLastBlockLevel env+ cmiGetLevel = getLastBlockLevel neMorleyClientEnv cmiGetApproximateBlockInterval :: ClientM (Time Second) cmiGetApproximateBlockInterval = liftIO $ do- pp <- runMorleyClientM env $ Client.getProtocolParameters+ pp <- runMorleyClientM neMorleyClientEnv $ Client.getProtocolParameters return . sec $ (unStringEncode $ ppMinimalBlockDelay pp) % 1 cmiAdvanceTime :: (KnownDivRat unit Second) => Time unit -> ClientM ()@@ -350,12 +353,12 @@ deltaSec' :: NominalDiffTime deltaSec' = secondsToNominalDiffTime $ toNum @Second deltaSec- t0 <- getLastBlockTimestamp env+ t0 <- getLastBlockTimestamp neMorleyClientEnv threadDelay deltaSec let go :: ClientM () go = do- now <- getLastBlockTimestamp env+ now <- getLastBlockTimestamp neMorleyClientEnv if (now `diffUTCTime` t0) >= deltaSec' then pass else threadDelay (sec 1) >> go@@ -363,7 +366,7 @@ cmiAdvanceToLevel :: (Natural -> Natural) -> ClientM () cmiAdvanceToLevel targetLevelFn = do- lastLevel <- getLastBlockLevel env+ lastLevel <- getLastBlockLevel neMorleyClientEnv let targetLevel = max (targetLevelFn lastLevel) lastLevel let skippedLevels = targetLevel - lastLevel -- In case we need to skip more than one level we'll jump ahead for@@ -386,21 +389,15 @@ cmiRunCode :: forall cp st vd. (HasRPCRepr st, T.IsoValue (AsRPC st)) => Sender -> RunCode cp st vd -> ClientM (AsRPC st)- cmiRunCode (Sender sender) (RunCode rcContract rcStorage rcParameter rcAmount rcLevel rcNow rcBalance rcSource) =- liftIO $ runMorleyClientM env do+ cmiRunCode (Sender sender) (RunCode rcContract rcParameter rcStorage rcAmount rcLevel rcNow rcBalance rcSource) =+ liftIO $ runMorleyClientM neMorleyClientEnv do -- Pattern match on the contract constructor to reveal- -- a proof of `NiceParameter cp` and `NiceStorage st`+ -- a proof of `NiceStorage st` L.Contract{} <- pure rcContract T.fromVal <$> Client.runContract Client.RunContractParameters { rcpContract = L.toMichelsonContract $ rcContract- , rcpStorage =- case rcStorage of- NotRPC v -> NotRPC $ toVal v- IsRPC v -> IsRPC $ toVal v- , rcpParameter =- case rcParameter of- NotRPC v -> NotRPC $ toVal v- IsRPC v -> IsRPC $ toVal v+ , rcpParameter = rcParameter+ , rcpStorage = rcStorage , rcpAmount = rcAmount , rcpBalance = rcBalance , rcpSource = rcSource@@ -408,13 +405,19 @@ , rcpNow = rcNow , rcpSender = Just sender }- \\ L.niceParameterEvi @cp \\ L.niceStorageEvi @st +clientFailure :: Builder -> ClientM a+clientFailure = throwM . CustomTestError . pretty+ comment :: Text -> ClientM () comment msg = liftIO $ putTextLn msg >> hFlush stdout -getAlias :: MorleyClientEnv -> Address -> ClientM Alias+getAlias+ :: L1AddressKind kind+ => MorleyClientEnv+ -> KindedAddress kind+ -> ClientM (Alias kind) getAlias env = liftIO . runMorleyClientM env . Client.getAlias . AddressResolved getLastBlockTimestamp :: MorleyClientEnv -> ClientM UTCTime@@ -426,7 +429,11 @@ bc <- liftIO $ runMorleyClientM env (Client.getBlockConstants HeadId) pure . Unsafe.fromIntegral @Int64 @Natural . bhnhLevel $ bcHeader bc -runOperationBatch :: MorleyClientEnv -> Address -> [OperationInfo ClevelandInput] -> ClientM [OperationInfo Result]+runOperationBatch+ :: MorleyClientEnv+ -> ImplicitAddress+ -> [OperationInfo ClevelandInput]+ -> ClientM [OperationInfo ClevelandResult] runOperationBatch env sender ops = do istRef <- ask ClientState{csMoneybagAddress=Moneybag moneybag} <- readIORef istRef@@ -535,16 +542,47 @@ snd <$> Client.runOperations (AddressResolved sender) ops' forM_ results $ \case- OpTransfer () -> pass+ OpTransfer _ -> pass OpOriginate addr -> do alias <- getAlias env addr comment $ "Originated smart contract '" +| alias |+ "' with address " <> pretty addr OpReveal () -> pass - return results+ mapM toClevelandResult results -dryRunOperations :: AddressOrAlias+toClevelandResult :: OperationInfo Result -> ClientM (OperationInfo ClevelandResult)+toClevelandResult = \case+ OpTransfer ops -> OpTransfer <$> mapM intOpEventToContractEvent ops+ OpOriginate ops -> pure $ OpOriginate ops+ OpReveal ops -> pure $ OpReveal ops++intOpEventToContractEvent :: IntOpEvent -> ClientM ContractEvent+intOpEventToContractEvent IntOpEvent{..} = do+ T.AsUType (ceType :: T.Notes t) <- either throwM (pure . toTy) $ fromExpression @U.T ioeType+ cePayload <- case ioePayload of+ Nothing -> pure Nothing+ Just payload -> case fromExpression @(T.Value t) . toExpression $ payload of+ Right value -> pure . Just $ SomeAnnotatedValue ceType value+ Left err ->+ clientFailure $ unlinesF+ [ "Failed to decode event payload expression."+ , "Payload expression:"+ , indentF 2 $ build (J.encodeToTextBuilder $ toExpression payload)+ , "Decoding error:"+ , indentF 2 $ build err+ ]+ pure $ ContractEvent+ { ceSource = ioeSource+ , ceTag = maybe "" unMText ioeTag+ , ..+ }+ where+ toTy :: U.T -> U.Ty+ toTy t = U.Ty t U.noAnn+++dryRunOperations :: ImplicitAddressOrAlias -> [OperationInfo Client.ClientInput] -> Client.MorleyClientM [(AppliedResult, Mutez)] dryRunOperations s = \case@@ -569,11 +607,12 @@ exceptionToTransferFailure :: RPC.ClientRpcError -> ClientM TransferFailure exceptionToTransferFailure = \case- RPC.ContractFailed addr expr -> return $ TransferFailure addr $ FailedWith (EOTVExpression expr) Nothing- RPC.BadParameter addr _ -> return $ TransferFailure addr BadParameter- RPC.EmptyTransaction addr -> return $ TransferFailure addr EmptyTransaction- RPC.ShiftOverflow addr -> return $ TransferFailure addr ShiftOverflow- RPC.GasExhaustion addr -> return $ TransferFailure addr GasExhaustion+ RPC.ContractFailed addr expr -> return $ TransferFailure (AddressAndAlias (MkAddress addr) Nothing) $+ FailedWith (EOTVExpression expr) Nothing+ RPC.BadParameter addr _ -> return $ TransferFailure (AddressAndAlias addr Nothing) BadParameter+ RPC.EmptyTransaction addr -> return $ TransferFailure (AddressAndAlias (MkAddress addr) Nothing) EmptyTransaction+ RPC.ShiftOverflow addr -> return $ TransferFailure (AddressAndAlias (MkAddress addr) Nothing) ShiftOverflow+ RPC.GasExhaustion addr -> return $ TransferFailure (AddressAndAlias (MkAddress addr) Nothing) GasExhaustion internalError -> throwM internalError exceptionHandler :: ClientM a -> ClientM a@@ -581,32 +620,7 @@ Left err -> exceptionToTransferFailure err >>= throwM Right res -> return res -runClientOrigination- :: MorleyClientEnv- -> Sender- -> ( Bool- -> Alias- -> AddressOrAlias- -> Mutez- -> U.Contract- -> U.Value- -> Maybe Mutez- -> Client.MorleyClientM (OperationHash, Address)- )- -> UntypedOriginateData- -> ClientM (OperationHash, Address)-runClientOrigination env (Sender sender) mkScenario (UntypedOriginateData{..}) = do- let originationScenario =- mkScenario True uodName (AddressResolved sender)- uodBalance uodContract uodStorage Nothing- -- Note that tezos key reveal operation cost an additional fee- -- so that's why we reveal keys in origination and transaction- -- rather than doing it before scenario execution- liftIO $ do- revealKeyUnlessRevealed env sender- runMorleyClientM env originationScenario--resolveSpecificOrDefaultAlias :: SpecificOrDefaultAlias -> ClientM Alias+resolveSpecificOrDefaultAlias :: SpecificOrDefaultAlias -> ClientM ImplicitAlias resolveSpecificOrDefaultAlias (SpecificAlias alias) = pure alias resolveSpecificOrDefaultAlias (DefaultAlias) = do stateRef <- ask@@ -614,13 +628,13 @@ writeIORef stateRef ist{ csDefaultAliasCounter = DefaultAliasCounter $ counter + 1 } pure $ mkDefaultAlias counter -setAddressRefillable :: Address -> ClientM ()+setAddressRefillable :: ImplicitAddress -> ClientM () setAddressRefillable addr = do stRef <- ask modifyIORef stRef $ \st@ClientState{..} -> st{csRefillableAddresses=Set.insert addr csRefillableAddresses} -isAddressRefillable :: Address -> ClientM Bool+isAddressRefillable :: ImplicitAddress -> ClientM Bool isAddressRefillable addr = do stRef <- ask Set.member addr . csRefillableAddresses <$> readIORef stRef@@ -631,7 +645,7 @@ convertOriginateUntypedData :: (MonadThrow m)- => UntypedOriginateData -> m Client.OriginationData+ => UntypedOriginateData 'NotLarge -> m Client.OriginationData convertOriginateUntypedData UntypedOriginateData{..} = do SomeContractAndStorage contract storage <- throwLeft . pure $ typeCheckingWith def $@@ -649,7 +663,7 @@ :: TransferData -> Client.TransactionData convertTransferData TransferData{ tdParameter = param :: p, ..} = Client.TransactionData Client.TD- { tdReceiver = toAddress tdTo+ { tdReceiver = toL1Address tdTo , tdAmount = tdAmount , tdEpName = tdEntrypoint , tdParam = toVal param@@ -657,7 +671,7 @@ } \\ niceParameterEvi @p -- | Runs 'Client.revealKeyUnlessRevealed' with given client environment.-revealKeyUnlessRevealed :: MorleyClientEnv -> Address -> IO ()+revealKeyUnlessRevealed :: MorleyClientEnv -> ImplicitAddress -> IO () revealKeyUnlessRevealed env addr = runMorleyClientM env $ -- We don't use password protected accounts in cleveland. Client.revealKeyUnlessRevealed addr Nothing
src/Test/Cleveland/Internal/Hedgehog.hs view
@@ -26,9 +26,7 @@ -- | Run an 'Scenario' via the "Morley.Michelson.Runtime" emulator, -- inside an @hedgehog@ property. testScenarioProps :: (HasCallStack, MonadIO m, MonadTest m) => Scenario PureM -> m ()-testScenarioProps = evalIO . \case- ScenarioCleveland s -> runClevelandT moneybagAlias s- ScenarioEmulated s -> runEmulatedT moneybagAlias s+testScenarioProps (ScenarioEmulated s) = evalIO $ runEmulatedT moneybagAlias s evalIO :: (HasCallStack, MonadIO m, MonadTest m) => IO a -> m a evalIO m = either (withFrozenCallStack failWithException) pure =<< liftIO (tryAll m)
src/Test/Cleveland/Internal/Pure.hs view
@@ -4,7 +4,6 @@ -- | Integration with integrational testing engine (pun intended). module Test.Cleveland.Internal.Pure ( PureM(..)- , runClevelandT , runEmulatedT -- * Capability implementations@@ -23,36 +22,31 @@ , emptyScenarioBranch -- * Optics- , psAliases+ , psSecretKeys , psDefaultAliasesCounter , psRefillableAddresses , psNow , psLevel , psMinBlockTime , psGState- , psContractsNames ) where -import Control.Lens (assign, at, makeLenses, modifying, to, (%=), (.=))+import Control.Lens (assign, at, each, makeLenses, modifying, to, (%=), (.=), (?=), (?~)) import Control.Lens.Unsound (lensProduct) import Control.Monad.Catch.Pure (CatchT, runCatchT) import Control.Monad.Writer (MonadWriter, WriterT, listen, runWriterT, tell) import Data.Constraint (Dict(..), withDict, (\\)) import Data.Default (def) import Data.Map qualified as Map-import Data.Monoid (Ap(..)) import Data.Ratio ((%)) import Data.Set qualified as Set-import Data.Singletons (sing)-import Data.Type.Equality (type (:~:)(Refl)) import Fmt (Buildable(..), Builder, build, pretty, unlinesF, (+|), (|+)) import Time (Second, toNum, toUnit) import Lorentz (Mutez, NiceComparable, pattern DefEpName) import Lorentz qualified as L import Lorentz.Entrypoints (HasEntrypointArg, TrustEpName(..), useHasEntrypointArg)-import Morley.AsRPC- (HasRPCRepr(AsRPC), MaybeRPC(..), notesAsRPC, replaceBigMapIds, rpcStorageScopeEvi, valueAsRPC)+import Morley.AsRPC (HasRPCRepr(AsRPC), notesAsRPC, rpcStorageScopeEvi, valueAsRPC) import Morley.Client (OperationInfo(..)) import Morley.Michelson.Interpret (InterpretError(..), InterpretResult(..), MichelsonFailed(..), MichelsonFailureWithStack(..))@@ -61,37 +55,40 @@ import Morley.Michelson.Runtime.Dummy (dummyLevel, dummyMaxSteps, dummyMinBlockTime, dummyNow, dummyOrigination) import Morley.Michelson.Runtime.GState- (GState(..), asBalance, genesisAddress, genesisSecretKey, gsAddressesL, gsChainIdL, gsCounterL,- gsVotingPowersL, initGState)-import Morley.Michelson.TypeCheck (TCError(..), typeCheckContractAndStorage, typeCheckingWith)+ (GState(..), genesisAddress, genesisSecretKey, gsChainIdL, gsContractAddressAliasesL,+ gsContractAddressesL, gsCounterL, gsImplicitAddressAliasesL, gsVotingPowersL, initGState,+ lookupBalance)+import Morley.Michelson.TypeCheck+ (BigMapFinder, TCError(..), TypeCheckOptions(..), typeCheckContractAndStorage,+ typeCheckValueRunCodeCompat, typeCheckingWith) import Morley.Michelson.Typed- (BigMapId(..), IsoValue, SingI, SomeAnnotatedValue(..), ToT, Value, Value'(..), castM,- dfsFoldMapValue, fromVal, requireEq, toVal)+ (BigMapId(..), IsoValue, SingI, SomeAnnotatedValue(..), SomeConstrainedValue(SomeValue),+ SomeVBigMap(..), SomeValue, ToT, Value, Value'(..), castM, dfsFoldMapValue, fromVal, toVal) import Morley.Michelson.Typed qualified as T-import Morley.Michelson.Typed.Operation (OriginationOperation(..), TransferOperation(..))+import Morley.Michelson.Typed.Operation+ (EmitOperation(..), OriginationOperation(..), TransferOperation(..)) import Morley.Michelson.Untyped qualified as U-import Morley.Tezos.Address (Address, detGenKeyAddress)-import Morley.Tezos.Address.Alias (Alias(..))+import Morley.Tezos.Address+import Morley.Tezos.Address.Alias import Morley.Tezos.Core (Timestamp, timestampPlusSeconds, unsafeSubMutez, zeroMutez) import Morley.Tezos.Crypto (SecretKey(..), detSecretKey, sign, toPublic) import Morley.Util.MismatchError import Morley.Util.Named +import Morley.Util.Bimap qualified as Bimap import Test.Cleveland.Internal.Abstract import Test.Cleveland.Internal.Exceptions (addCallStack, catchWithCallStack, throwWithCallStack) import Test.Cleveland.Lorentz import Test.Cleveland.Util (ceilingUnit) data PureState = PureState- { _psAliases :: Aliases+ { _psSecretKeys :: Map ImplicitAddress SecretKey , _psDefaultAliasesCounter :: DefaultAliasCounter- , _psRefillableAddresses :: Set Address+ , _psRefillableAddresses :: Set ImplicitAddress , _psNow :: Timestamp , _psLevel :: Natural , _psMinBlockTime :: Natural , _psGState :: GState- , _psContractsNames :: Map Address Text- -- ^ Map from contracts addresses to human-readable names. } deriving stock (Eq, Show) @@ -99,69 +96,49 @@ get = ask >>= readIORef put = (ask >>=) . flip writeIORef -data AddressName = AddressName (Maybe Text) Address deriving stock (Show)- newtype PureM a = PureM { unPureM :: ReaderT (IORef PureState) (CatchT (WriterT LogsInfo IO)) a } deriving newtype (Functor, Applicative, Monad, MonadIO, MonadThrow, MonadCatch, MonadReader (IORef PureState), MonadWriter LogsInfo, MonadFail) -type Aliases = Map Alias AliasData---- | Datatype to store alias data, we store optional 'SecretKey' in addition--- to 'Address' in order to support bytes signing.-data AliasData = AliasData- { adAddress :: Address- , adMbSecretKey :: Maybe SecretKey- }- deriving stock (Eq, Show)- data TestError = UnexpectedTypeCheckError TCError | UnexpectedStorageType (MismatchError T.T)- | UnexpectedBigMapKeyType (MismatchError T.T)- | UnexpectedBigMapValueType (MismatchError T.T)+ | UnexpectedBigMapType Natural (MismatchError T.T) | CustomTestError Text deriving stock Show makeLenses ''PureState -instance Buildable AddressName where- build (AddressName mbName addr) =- build addr +| maybe "" (\cName -> " (" +|cName |+ ")") mbName- instance Buildable TestError where- build (UnexpectedTypeCheckError tcErr) =- "Unexpected type check error. Reason: " +| tcErr |+ ""- build (UnexpectedStorageType merr) =- "Unexpected storage type.\n" +| merr |+ ""- build (UnexpectedBigMapKeyType merr) =- "Unexpected big map key type.\n" +| merr |+ ""- build (UnexpectedBigMapValueType merr) =- "Unexpected big map value type.\n" +| merr |+ ""- build (CustomTestError msg) = pretty msg+ build = \case+ UnexpectedTypeCheckError tcErr ->+ "Unexpected type check error. Reason: " +| tcErr |+ ""+ UnexpectedStorageType merr ->+ "Unexpected storage type.\n" +| merr |+ ""+ UnexpectedBigMapType bigMapId mismatchError ->+ unlinesF+ [ "A big_map with the ID " +| bigMapId |+ " was found, but it does not have the expected type."+ , build mismatchError+ ]+ CustomTestError msg -> pretty msg instance Exception TestError where displayException = pretty -moneybagAlias :: Alias-moneybagAlias = Alias "moneybag"--runEmulatedT :: Alias -> EmulatedT PureM a -> IO a-runEmulatedT moneybagAlias' scenario =- runClevelandT moneybagAlias' do- clevelandCaps <- ask- lift . runReaderT scenario $ EmulatedCaps emulatedImpl clevelandCaps+moneybagAlias :: ImplicitAlias+moneybagAlias = ImplicitAlias "moneybag" -runClevelandT :: Alias -> ClevelandT PureM a -> IO a-runClevelandT moneybagAlias' scenario = do- let caps = ClevelandCaps+runEmulatedT :: ImplicitAlias -> EmulatedT PureM a -> IO a+runEmulatedT moneybagAlias' scenario = do+ let clevelandCaps = ClevelandCaps { ccSender = Sender genesisAddress , ccMoneybag = Moneybag genesisAddress , ccMiscCap = clevelandMiscImpl , ccOpsCap = clevelandOpsImpl }+ caps = EmulatedCaps emulatedImpl clevelandCaps let pureM = runReaderT scenario caps env <- newIORef (initEnv moneybagAlias') (res, _logs) <- runWriterT $ runCatchT $ runReaderT (unPureM pureM) env@@ -187,32 +164,41 @@ ClevelandOpsImpl { coiRunOperationBatch = mapM \case OpOriginate UntypedOriginateData{..} -> do- ref <- originate uodContract (pretty uodName) uodStorage uodBalance- OpOriginate <$> saveAlias uodName (toAddress ref) Nothing+ OpOriginate <$> originate uodContract uodName uodStorage uodBalance OpTransfer TransferData{..} -> do let fromAddr = #from :! sender- let toAddr = #to :! toAddress tdTo+ let toAddr = #to :! toL1Address tdTo refillable <- isAddressRefillable sender when refillable $ do balance <- getBalance sender when (balance < tdAmount) $ do let moneybag = #from :! genesisAddress toSender = #to :! sender- transfer @() moneybag toSender (unsafeSubMutez tdAmount balance)+ void $ transfer @() moneybag toSender (unsafeSubMutez tdAmount balance) (TrustEpName DefEpName) () -- Here @toAddr@ is 'Address', so we can not check anything -- about it and assume that entrypoint is correct. We pass -- unit as contract parameter because it won't be checked -- anyway.- transfer @() fromAddr toAddr tdAmount+ emitOps <- transfer @() fromAddr toAddr tdAmount (TrustEpName tdEntrypoint) tdParameter - return $ OpTransfer ()+ return $ OpTransfer $ emitOpToContractEvent <$> emitOps OpReveal{} -> do -- We do not care about reveals in our Morley runtime return $ OpReveal () } +emitOpToContractEvent :: EmitOperation -> ContractEvent+emitOpToContractEvent EmitOperation{eoEmit=T.Emit{..},..} = ContractEvent+ { cePayload = case T.notesT emNotes of+ -- A dirty hack to match reference+ T.TUnit -> Nothing+ _ -> Just $ SomeAnnotatedValue emNotes emValue+ , ceTag = emTag+ , ceSource = eoSource+ }+ clevelandMiscImpl :: ClevelandMiscImpl PureM clevelandMiscImpl = mapClevelandMiscImplExceptions (addCallStack . exceptionHandler)@@ -221,19 +207,13 @@ Right res -> pure res Left (err :: SomeException) -> throwM err - , cmiResolveAddress = resolve+ , cmiResolveAddress = \case+ a@ImplicitAlias{} -> resolveImplicit a+ a@ContractAlias{} -> resolveContract a , cmiSignBytes = \bs addr -> do- -- TODO [#248]: make sure this performs fast- alias <- getAlias addr- aliases <- use psAliases- let mbMbSk = Map.lookup alias aliases- mbSk <- maybe (unknownAlias alias) (pure . adMbSecretKey) mbMbSk- case mbSk of- Nothing ->- cmiFailure $- "Given address doesn't have known associated secret key: " <> build alias- Just sk -> liftIO $ sign sk bs+ sk <- getSecretKey addr+ liftIO $ sign sk bs , cmiGenKey = \sodAlias -> do alias <- resolveSpecificOrDefaultAlias sodAlias@@ -242,23 +222,15 @@ , cmiGenFreshKey = \sodAlias -> do alias <- resolveSpecificOrDefaultAlias sodAlias- aliases <- use psAliases- let mbSk = Map.lookup alias aliases- smartGenKey (adAddress <$> mbSk) alias+ existingAddr <- use (psGState . gsImplicitAddressAliasesL . at alias)+ smartGenKey existingAddr alias , cmiOriginateLargeUntyped = originateUntyped -- Comments are not supported by integrational testing engine (yet). , cmiComment = const pass , cmiGetPublicKey = \addr -> do- aliases <- use psAliases- let mbAliasInfo = fmap snd $ find (\(_, AliasData addr' _) -> addr == addr') (Map.toList aliases)- aliasInfo <- maybe (unknownAddress addr) pure mbAliasInfo- case adMbSecretKey aliasInfo of- Nothing ->- cmiFailure $- "Given address doesn't have known associated public key: " <> build addr- Just sk -> pure $ toPublic sk+ toPublic <$> getSecretKey addr , cmiGetDelegate = \addr -> do ContractState _ _ _ delegate <- contractStorage addr pure delegate@@ -278,20 +250,17 @@ , cmiAttempt = try , cmiThrow = throwM , cmiMarkAddressRefillable = setAddressRefillable- , cmiGetBalance = getBalance- , cmiEmulatedImpl = pure $ Just emulatedImpl+ , cmiGetBalance = \(MkConstrainedAddress a) -> getBalance a+ , cmiUnderlyingImpl = pure $ Left emulatedImpl+ , cmiFailure = failure , .. } where- cmiFailure :: forall a. Builder -> PureM a- cmiFailure = throwM . CustomTestError . pretty- setAddressRefillable addr = psRefillableAddresses %= Set.insert addr - originateUntyped :: Sender -> UntypedOriginateData -> PureM Address+ originateUntyped :: Sender -> UntypedOriginateData 'IsLarge -> PureM ContractAddress originateUntyped _ UntypedOriginateData {..} = do- ref <- originate uodContract (pretty uodName) uodStorage uodBalance- saveAlias uodName (toAddress ref) Nothing+ originate uodContract uodName uodStorage uodBalance cmiGetBigMapValueMaybe :: forall k v.@@ -300,6 +269,9 @@ -> k -> PureM (Maybe v) cmiGetBigMapValueMaybe (BigMapId bmId) k = runMaybeT do+ -- The RPC does not distinguish between "the bigmap does not exist"+ -- and "the bigmap exists, but the key doesn't", so we mimic the RPC's behaviour here.+ -- We simply return `Nothing` in both cases. VBigMap _ bigMap <- findBigMapByIdMaybe @(ToT k) @(ToT v) bmId hoistMaybe $ fromVal @v <$> Map.lookup (toVal k) bigMap @@ -312,59 +284,6 @@ VBigMap _ bigMap <- findBigMapByIdMaybe @(ToT k) @(ToT v) bmId pure $ fromVal @v <$> Map.elems bigMap - findBigMapById- :: forall k v. (SingI v, SingI k)- => Natural -> PureM (Value ('T.TBigMap k v))- findBigMapById bigMapId =- runMaybeT (findBigMapByIdMaybe @k @v bigMapId) >>= maybe notFound pure- where- notFound = cmiFailure $ "BigMap with ID " <> build bigMapId <> " not found."--- -- | Traverse storage values of all contracts and looks for a big_map with the given ID.- -- If multiple big_maps with the given ID are found, it fails with error.- findBigMapByIdMaybe- :: forall k v. (SingI v, SingI k)- => Natural -> MaybeT PureM (Value ('T.TBigMap k v))- findBigMapByIdMaybe bigMapId = MaybeT do- addresses <- use $ psGState . gsAddressesL . to Map.elems-- let Ap result =- flip foldMap addresses \case- ASContract ContractState{csStorage} ->- findBigMapInStorage csStorage bigMapId- ASSimple {} -> Ap $ Right []-- case result of- -- The RPC does not distinguish between "the bigmap does not exist"- -- and "the bigmap exists, but the key doesn't", so we mimic the RPC's behaviour here.- -- We simply return `Nothing` in both cases.- Right [] -> pure Nothing- Right [bigMap] -> pure $ Just bigMap- Right bigMaps ->- error $ pretty $ unlinesF @_ @Builder- [ "Expected all big_maps to have unique IDs, but found " +| length bigMaps |+ " big_maps with the ID " +| bigMapId |+ "."- , "This is most likely a bug."- ]- Left (err :: TestError) -> throwM err-- -- | Traverse a storage value and looks for a big_map with the given ID.- -- If multiple big_maps with the given ID are found, they'll all be returned.- findBigMapInStorage- :: forall k v st. (SingI k, SingI v)- => Value st -> Natural -> Ap (Either TestError) [Value ('T.TBigMap k v)]- findBigMapInStorage storage bigMapId =- dfsFoldMapValue- (\v -> case v of- VBigMap (Just bigMapId') (_ :: Map (Value k') (Value v'))- | bigMapId == bigMapId' -> do- Refl <- requireEq @k' @k (Ap . Left . UnexpectedBigMapKeyType)- Refl <- requireEq @v' @v (Ap . Left . UnexpectedBigMapValueType)- pure [v]- _ -> Ap $ Right []- )- storage- -- | In a real chain, when we retrieve a contract's storage via the Tezos RPC, -- the storage expression will have all the big_maps replaced with their respective big_map IDs. --@@ -375,7 +294,7 @@ -- * A contract with big_maps in its storage is originated -- * A transfer is made and the parameter contains big_maps -- * A contract's code is run and it calls `EMPTY_BIG_MAP`, `DUP` or `DUP n`.- cmiGetSomeStorage :: Address -> PureM SomeAnnotatedValue+ cmiGetSomeStorage :: ContractAddress -> PureM SomeAnnotatedValue cmiGetSomeStorage addr = do ContractState _ contract (storage :: Value t) _ <- contractStorage addr pure $@@ -384,23 +303,28 @@ (valueAsRPC storage) \\ rpcStorageScopeEvi @t - getAlias :: Address -> PureM Alias- getAlias addr = do- aliases <- use psAliases- let maybeAlias = (fmap fst . find (\(_, AliasData addr' _) -> addr == addr') . Map.toList) aliases- maybe (unknownAddress addr) pure maybeAlias-- -- Generate a fresh address which was never generated for given alias.- -- If the address is not saved, we use the alias as its seed.- -- Otherwise we concatenate the alias with the saved address.- smartGenKey :: Maybe Address -> Alias -> PureM Address- smartGenKey existingAddr alias@(Alias aliasTxt) =+ -- Generate a fresh address for a given alias.+ --+ -- If this alias is not yet associated with any address,+ -- we use the alias as the seed for generating a brand new address.+ --+ -- If this alias is already associated with an address,+ -- then we have to use a _different_ seed to guarantee we'll get a brand new address.+ -- Therefore, we concatenate the alias with the existing address and use the+ -- result as a seed for generating a brand new address.+ smartGenKey :: Maybe ImplicitAddress -> ImplicitAlias -> PureM ImplicitAddress+ smartGenKey existingAddr alias@(ImplicitAlias aliasTxt) = do let seed = maybe aliasTxt (mappend aliasTxt . pretty) existingAddr sk = detSecretKey (encodeUtf8 seed) addr = detGenKeyAddress (encodeUtf8 seed)- in saveAlias alias addr $ Just sk + -- Save alias/address association.+ psGState . gsImplicitAddressAliasesL . at alias ?= addr+ -- Save the address's secret key.+ psSecretKeys . at addr .= Just sk+ pure addr+ resolveSpecificOrDefaultAlias (SpecificAlias alias) = return alias resolveSpecificOrDefaultAlias DefaultAlias = do@@ -411,12 +335,13 @@ cmiRunCode :: forall cp st vd. (HasRPCRepr st, T.IsoValue (AsRPC st)) => Sender -> RunCode cp st vd -> PureM (AsRPC st)- cmiRunCode (Sender sender) (RunCode rcContract rcStorage rcParameter rcAmount rcLevel rcNow rcBalance rcSource) = do+ cmiRunCode (Sender sender) (RunCode rcContract rcParameter rcStorage rcAmount rcLevel rcNow rcBalance rcSource) = do -- Pattern match on the contract constructor to reveal -- a proof of `NiceParameter cp` and `NiceStorage st` L.Contract{} <- pure rcContract- param <- maybeRPCToVal rcParameter- storage <- maybeRPCToVal rcStorage+ param <- typeCheckVal @(ToT cp) rcParameter+ storage <- typeCheckVal @(ToT st) rcStorage+ (now, level) <- use $ psNow `lensProduct` psLevel psNow %= maybe id const rcNow psLevel %= maybe id const rcLevel@@ -428,15 +353,15 @@ \\ L.niceStorageEvi @st \\ L.niceParameterEvi @cp - esSourceAddress .= rcSource+ esSourceAddress .= (MkConstrainedAddress <$> rcSource) counter1 <- use $ esGState . gsCounterL let overrideContractBalance = Just rcBalance executeTransfer (#isGlobalOp :! False) overrideContractBalance def $ TransferOperation- { toDestination = contractAddr+ { toDestination = MkAddress contractAddr , toCounter = counter1 , toTxData = TxData- { tdSenderAddress = sender+ { tdSenderAddress = MkConstrainedAddress sender , tdParameter = TxTypedParam param \\ L.niceParameterEvi @cp , tdEntrypoint = DefEpName , tdAmount = rcAmount@@ -449,49 +374,83 @@ Left executorError -> throwEE executorError Right (executorRes, contractAddr) -> do -- Find the storage of the contract and return it in its RPC representation.- case executorRes ^. erGState . gsAddressesL . at contractAddr of+ case executorRes ^. erGState . gsContractAddressesL . at contractAddr of Nothing ->- cmiFailure $ "Internal error: failed to find contract: '" +| contractAddr |+ "'"- Just (ASSimple {}) ->- cmiFailure $ "Internal error: expected address to belong to a contract: '" +| contractAddr |+ "'"- Just (ASContract (ContractState _ _ (finalStorage :: Value actualSt) _)) -> do+ failure $ "Internal error: failed to find contract: '" +| contractAddr |+ "'"+ Just (ContractState _ _ (finalStorage :: Value actualSt) _) -> do finalStorage' <- castM @actualSt @(ToT st) finalStorage (throwM . UnexpectedStorageType) pure $ fromVal $ valueAsRPC finalStorage' where- maybeRPCToVal :: MaybeRPC v -> PureM (Value (ToT v))- maybeRPCToVal = \case- NotRPC v -> pure $ toVal v- IsRPC v -> replaceBigMapIds findBigMapById sing $ toVal v+ typeCheckVal :: forall t. SingI t => U.Value -> PureM (Value t)+ typeCheckVal untypedVal = do+ bigMapFinder <- mkBigMapFinder+ let res =+ typeCheckingWith (TypeCheckOptions False False) $+ typeCheckValueRunCodeCompat bigMapFinder untypedVal+ case res of+ Right val -> pure val+ Left tcErr -> throwM $ UnexpectedTypeCheckError tcErr -isAddressRefillable :: Address -> PureM Bool+mkBigMapFinder :: PureM BigMapFinder+mkBigMapFinder = do+ pureState <- get++ pure \bigMapId ->+ pureState ^?+ psGState . gsContractAddressesL . each . to getContractStorage . to (getBigMapsWithId bigMapId) . each+ where+ getContractStorage :: ContractState -> SomeValue+ getContractStorage (ContractState _ _ storage _) = SomeValue storage++ getBigMapsWithId :: Natural -> SomeValue -> [SomeVBigMap]+ getBigMapsWithId bigMapId (SomeValue val) =+ dfsFoldMapValue+ (\v -> case v of+ VBigMap (Just bigMapId') _ | bigMapId' == bigMapId -> [SomeVBigMap v]+ _ -> []+ )+ val++-- | Traverse storage values of all contracts and looks for a big_map with the given ID.+findBigMapByIdMaybe+ ::forall k v. (SingI v, SingI k)+ => Natural -> MaybeT PureM (Value ('T.TBigMap k v))+findBigMapByIdMaybe bigMapId = do+ SomeVBigMap (v@VBigMap{} :: Value t) <- MaybeT $ mkBigMapFinder <*> pure bigMapId+ castM @t @('T.TBigMap k v) v $ throwM . UnexpectedBigMapType bigMapId++isAddressRefillable :: ImplicitAddress -> PureM Bool isAddressRefillable addr = Set.member addr <$> use psRefillableAddresses -getBalance :: Address -> PureM Mutez+getBalance :: L1AddressKind kind => KindedAddress kind -> PureM Mutez getBalance addr = do- GState{..} <- use psGState- return $ maybe zeroMutez asBalance $ Map.lookup addr gsAddresses--saveAlias :: Alias -> Address -> Maybe SecretKey -> PureM Address-saveAlias name addr mbSk = do- psAliases %= Map.insert name (AliasData addr mbSk)- pure addr+ gs <- use psGState+ pure $ fromMaybe zeroMutez $ lookupBalance addr gs exceptionHandler :: PureM a -> PureM a exceptionHandler action = try action >>= \case Left err -> exceptionToTransferFailure err >>= throwM Right res -> return res where- exceptionToTransferFailure :: ExecutorError' AddressName -> PureM TransferFailure+ exceptionToTransferFailure :: ExecutorError' AddressAndAlias -> PureM TransferFailure exceptionToTransferFailure err = case err of- EEZeroTransaction addr -> return $ TransferFailure (addrNameToAddr addr) EmptyTransaction- EEIllTypedParameter addr _ -> return $ TransferFailure (addrNameToAddr addr) BadParameter- EEUnexpectedParameterType addr _ -> return $ TransferFailure (addrNameToAddr addr) BadParameter+ EEZeroTransaction addr -> return $+ TransferFailure addr EmptyTransaction+ EEIllTypedParameter addr _ -> return $+ TransferFailure addr BadParameter+ EEUnexpectedParameterType addr _ -> return $+ TransferFailure addr BadParameter EEInterpreterFailed addr (InterpretError (MichelsonFailureWithStack{..}, _)) -> case mfwsFailed of- MichelsonFailedWith val -> return $ TransferFailure (addrNameToAddr addr) $ FailedWith (EOTVTypedValue val) (Just mfwsErrorSrcPos)- MichelsonArithError (T.ShiftArithError{}) -> return $ TransferFailure (addrNameToAddr addr) ShiftOverflow- MichelsonArithError (T.MutezArithError errType _ _) -> return $ TransferFailure (addrNameToAddr addr) $ MutezArithError errType- MichelsonGasExhaustion -> return $ TransferFailure (addrNameToAddr addr) GasExhaustion+ MichelsonFailedWith val -> return $+ TransferFailure addr $+ FailedWith (EOTVTypedValue val) (Just mfwsErrorSrcPos)+ MichelsonArithError (T.ShiftArithError{}) -> return $+ TransferFailure addr ShiftOverflow+ MichelsonArithError (T.MutezArithError errType _ _) -> return $+ TransferFailure addr $ MutezArithError errType+ MichelsonGasExhaustion -> return $+ TransferFailure addr GasExhaustion _ -> throwM err _ -> throwM err @@ -504,34 +463,34 @@ => addr -> PureM st getStorageImpl addr = do withDict (pickNiceStorage @st addr) $ do- ContractState _ _ (storage :: Value actualT) _ <- contractStorage (toAddress addr)+ ContractState _ _ (storage :: Value actualT) _ <- contractStorage (toContractAddress addr) val <- castM @actualT @(ToT st) storage (throwM . UnexpectedStorageType) pure $ T.fromVal val -- Attempt to retrieve a ContractState given for the given address. Fails if the -- address is unknown or the address is a simple address (contract without -- code and storage).-contractStorage :: Address -> PureM ContractState+contractStorage :: ContractAddress -> PureM ContractState contractStorage addr = do GState{..} <- use psGState- case Map.lookup addr gsAddresses of- Just (ASContract contractState) -> pure contractState- Just (ASSimple {}) -> throwM . CustomTestError $- "Expected address to be contract with storage, but it's a simple address: " <> pretty addr+ case Map.lookup addr gsContractAddresses of+ Just contractState -> pure contractState Nothing -> unknownAddress addr -resolve :: Alias -> PureM Address-resolve name = do- aliases <- use psAliases- let maybeAddress = Map.lookup name aliases- maybe (unknownAlias name) (pure . adAddress) maybeAddress+resolveImplicit :: ImplicitAlias -> PureM ImplicitAddress+resolveImplicit alias = do+ use (psGState . gsImplicitAddressAliasesL . at alias) >>= maybe (unknownAlias alias) pure -unknownAddress :: Address -> PureM whatever+resolveContract :: ContractAlias -> PureM ContractAddress+resolveContract alias = do+ use (psGState . gsContractAddressAliasesL . at alias) >>= maybe (unknownAlias alias) pure++unknownAddress :: KindedAddress kind -> PureM whatever unknownAddress = throwM . CustomTestError . mappend "Unknown address provided: " . pretty -unknownAlias :: Alias -> PureM whatever+unknownAlias :: Alias kind -> PureM whatever unknownAlias = throwM . CustomTestError . mappend "Unknown address alias: " . pretty@@ -546,32 +505,34 @@ appendScenarioBranch brName (ScenarioBranchName branches) = ScenarioBranchName (brName : branches) +failure :: forall a. Builder -> PureM a+failure = throwM . CustomTestError . pretty++getSecretKey :: ImplicitAddress -> PureM SecretKey+getSecretKey addr = do+ use (psSecretKeys . at addr) >>= \case+ Nothing -> unknownAddress addr+ Just sk -> pure sk+ ---------------------------------------------------------------------------- -- Support functions ---------------------------------------------------------------------------- -initAliases :: Alias -> Aliases-initAliases alias = one ( alias- , AliasData genesisAddress $- Just $ genesisSecretKey- )--initEnv :: Alias -> PureState+initEnv :: ImplicitAlias -> PureState initEnv alias = PureState- { _psAliases = initAliases alias+ { _psSecretKeys = one (genesisAddress, genesisSecretKey) , _psDefaultAliasesCounter = DefaultAliasCounter 0 , _psRefillableAddresses = Set.empty , _psNow = dummyNow , _psLevel = dummyLevel- , _psGState = initGState+ , _psGState = initGState & gsImplicitAddressAliasesL . at alias ?~ genesisAddress , _psMinBlockTime = dummyMinBlockTime- , _psContractsNames = Map.empty } failedInsideBranch :: Text -> SomeException -> FailedInBranch failedInsideBranch name err = case fromException @FailedInBranch err of- Just (FailedInBranch branch failure) ->- FailedInBranch (appendScenarioBranch name branch) failure+ Just (FailedInBranch branch exception) ->+ FailedInBranch (appendScenarioBranch name branch) exception Nothing -> FailedInBranch (appendScenarioBranch name emptyScenarioBranch) err @@ -582,12 +543,12 @@ transfer :: forall cp vd epRef epArg addr. (HasEntrypointArg cp epRef epArg, T.IsoValue epArg, L.ToTAddress cp vd addr)- => "from" :! Address+ => "from" :! ImplicitAddress -> "to" :! addr -> Mutez -> epRef -> epArg- -> PureM ()+ -> PureM [EmitOperation] transfer (arg #from -> from) (arg #to -> toAddr) money epRef param = let L.TAddress to' = L.toTAddress @cp @vd toAddr in case useHasEntrypointArg @cp @epRef @epArg epRef of@@ -597,7 +558,7 @@ { toDestination = to' , toCounter = 0 , toTxData = TxData- { tdSenderAddress = from+ { tdSenderAddress = MkConstrainedAddress from , tdParameter = withDict (T.properParameterEvi @(ToT epArg)) $ TxTypedParam (T.toVal param) , tdEntrypoint = epName@@ -607,22 +568,30 @@ -- | Originate a contract with given initial storage and balance. Its -- address is returned.-originate :: U.Contract -> Text -> U.Value -> Mutez -> PureM Address-originate uContract contractName uStorage balance =+originate :: U.Contract -> ContractAlias -> U.Value -> Mutez -> PureM ContractAddress+originate uContract alias uStorage balance = case typeCheckingWith def $ typeCheckContractAndStorage uContract uStorage of Left tcErr -> throwM $ UnexpectedTypeCheckError tcErr Right (T.SomeContractAndStorage contract storage) -> do counter <- gsCounter <$> use psGState- address <- registerInterpretation . executeGlobalOrigination $- (dummyOrigination storage contract counter) { ooBalance = balance }-- psContractsNames %= Map.insert address contractName- return address+ registerInterpretation . executeGlobalOrigination $+ (dummyOrigination storage contract counter)+ { ooBalance = balance+ , ooAlias = Just alias+ } throwEE :: ExecutorError -> PureM a-throwEE err = do- st <- get- throwM $ flip addrToAddrName st <$> err+throwEE err =+ -- Replace all `Address`es with `AddressAndAlias` in the error and throw it.+ traverse addrToAddressAndAlias err >>= throwM+ where+ addrToAddressAndAlias :: Address -> PureM AddressAndAlias+ addrToAddressAndAlias addr@(MkAddress kindedAddr) =+ case kindedAddr of+ ContractAddress{} ->+ use $ psGState . gsContractAddressAliasesL . Bimap.flipped . at kindedAddr . to (AddressAndAlias addr)+ _ ->+ pure $ AddressAndAlias addr Nothing -- | Runs a set of operations and updates the engine's state. registerInterpretation :: ExecutorM a -> PureM a@@ -652,10 +621,3 @@ gState <- use psGState minBlockTime <- use psMinBlockTime pure $ runExecutorM now level minBlockTime dummyMaxSteps gState action--addrToAddrName :: Address -> PureState -> AddressName-addrToAddrName addr iState =- AddressName (Map.lookup addr (iState ^. psContractsNames)) addr--addrNameToAddr :: AddressName -> Address-addrNameToAddr (AddressName _ addr) = addr
src/Test/Cleveland/Internal/Scenario.hs view
@@ -2,42 +2,64 @@ -- SPDX-License-Identifier: LicenseRef-MIT-OA module Test.Cleveland.Internal.Scenario- ( Scenario(..)- , scenario+ ( Scenario+ , Scenario'(..)+ , MonadScenario(..) , scenarioEmulated+ , scenarioNetwork , withInitialNow , withInitialLevel , withMinBlockTime , withChainId ) where +import Control.Monad.Reader (withReaderT)+ import Morley.Michelson.Runtime.GState (gsChainIdL) import Morley.Tezos.Core qualified as TC import Test.Cleveland.Internal.Abstract+import Test.Cleveland.Internal.Client import Test.Cleveland.Internal.Pure --- | A type representing a finalized scenario-data Scenario m where- ScenarioCleveland :: ClevelandT m () -> Scenario m- ScenarioEmulated :: EmulatedT PureM () -> Scenario PureM+-- | A convenience type synonym for `Scenario'` that has 'MonadScenario'+-- constraint baked in.+type Scenario m = MonadScenario m => Scenario' m --- | Finalize a generic cleveland scenario.-scenario :: ClevelandT m () -> Scenario m-scenario = ScenarioCleveland+-- | A type representing a finalized scenario. Usually, when using this type+-- with a polymorphic argument, an additional 'MonadScenario' constraint on the+-- argument is required.+--+-- To avoid annotating with 'MonadScenario' everywhere, consider using+-- 'Scenario' instead when possible.+data Scenario' m where+ ScenarioEmulated :: EmulatedT PureM () -> Scenario' PureM+ ScenarioNetwork :: NetworkT ClientM () -> Scenario' ClientM +-- | Typeclass for base monads that can implement a scenario.+class MonadFail m => MonadScenario m where+ -- | Finalize a generic cleveland scenario.+ scenario :: ClevelandT m () -> Scenario' m++instance MonadScenario PureM where+ scenario = ScenarioEmulated . withReaderT (view clevelandCapsL)++instance MonadScenario ClientM where+ scenario = ScenarioNetwork . withReaderT (view clevelandCapsL)+ -- | Finalize a scenario that needs emulator-only features.-scenarioEmulated :: EmulatedT PureM () -> Scenario PureM+scenarioEmulated :: EmulatedT PureM () -> Scenario' PureM scenarioEmulated = ScenarioEmulated +-- | Finalize a scenario that needs network-only features.+scenarioNetwork :: NetworkT ClientM () -> Scenario' ClientM+scenarioNetwork = ScenarioNetwork+ withModifiedState :: (PureState -> PureState)- -> Scenario PureM- -> Scenario PureM-withModifiedState modfn = \case- ScenarioEmulated emulated ->- ScenarioEmulated $ lift (modify modfn) >> emulated- ScenarioCleveland cleveland ->- ScenarioCleveland $ lift (modify modfn) >> cleveland+ -> Scenario' PureM+ -> Scenario' PureM+withModifiedState modfn (ScenarioEmulated emulated) =+ ScenarioEmulated $ lift (modify modfn) >> emulated -- | Use with an emulated 'Scenario' to configure the initial @now@ value in tests. --@@ -46,27 +68,27 @@ -- > testScenarioOnEmulator "Testname" $ withInitialNow (Timestamp 10000000) $ scenario $ tests withInitialNow :: TC.Timestamp- -> Scenario PureM- -> Scenario PureM+ -> Scenario' PureM+ -> Scenario' PureM withInitialNow = withModifiedState . set psNow -- | Similar to 'withInitialNow' but for the initial level withInitialLevel :: Natural- -> Scenario PureM- -> Scenario PureM+ -> Scenario' PureM+ -> Scenario' PureM withInitialLevel = withModifiedState . set psLevel -- | Similar to 'withInitialNow' but for the @MINIMAL_BLOCK_DELAY@ protocol constant. withMinBlockTime :: Natural- -> Scenario PureM- -> Scenario PureM+ -> Scenario' PureM+ -> Scenario' PureM withMinBlockTime = withModifiedState . set psMinBlockTime -- | Similar to 'withInitialNow' but for the chain id withChainId :: TC.ChainId- -> Scenario PureM- -> Scenario PureM+ -> Scenario' PureM+ -> Scenario' PureM withChainId = withModifiedState . set (psGState . gsChainIdL)
src/Test/Cleveland/Lorentz.hs view
@@ -23,6 +23,9 @@ , chNiceParameterEvi , chNiceStorageEvi + , ToContractAddress (..)+ , ToL1Address (..)+ , ToL1TAddress (..) , ToStorageType (..) -- * Conversions
src/Test/Cleveland/Lorentz/Ticketer.hs view
@@ -12,6 +12,7 @@ import Prelude (HasCallStack) import Test.Cleveland+import Test.Cleveland.Internal.Actions.Transfer -- | A contract that emits the desired tickets. --@@ -47,14 +48,14 @@ -- | Run a contract indirectly via calling the given ticketer contract. ----- The target contract will recieve a ticket and some payload. The exact+-- The target contract will receive a ticket and some payload. The exact -- structure of the passed argument is determined by the ticketer contract. callViaTicketer :: forall targetArg payload td targetAddr ticketerParam ticketerAddr m. ( HasCallStack- , MonadOps m+ , MonadTransfer m , ticketerParam ~ View_ (payload, (Natural, td)) targetArg- , ToTAddress ticketerParam () ticketerAddr+ , ToL1TAddress ticketerParam () ticketerAddr , ToContractRef targetArg targetAddr , NiceParameterFull ticketerParam )@@ -65,5 +66,5 @@ -> payload -- ^ Main argument passed to the ticketer -> m () callViaTicketer ticketer ticketAmount ticketData target payload =- call @ticketerParam @() ticketer CallDefault- (mkView_ (payload, (ticketAmount, ticketData)) target)+ transfer (toL1TAddress @ticketerParam @() ticketer) $ calling def $+ mkView_ (payload, (ticketAmount, ticketData)) target
src/Test/Cleveland/Lorentz/Types.hs view
@@ -6,7 +6,11 @@ ( ContractHandle (..) , chNiceParameterEvi , chNiceStorageEvi+ , L1TAddress (..) + , ToContractAddress (..)+ , ToL1Address (..)+ , ToL1TAddress (..) , ToStorageType (..) , NiceParameter@@ -28,6 +32,8 @@ import Lorentz.Address import Lorentz.Constraints import Morley.Michelson.Typed qualified as T+import Morley.Tezos.Address+import Morley.Tezos.Address.Alias -- | Handle to a contract. --@@ -40,8 +46,8 @@ data ContractHandle (cp :: Type) (st :: Type) (vd :: Type) = (NiceParameter cp, NiceStorage st, NiceViewsDescriptor vd) => ContractHandle- { chContractName :: Text- , chAddress :: Address+ { chContractName :: ContractAlias+ , chAddress :: ContractAddress } deriving stock instance Show (ContractHandle cp st vd)@@ -51,7 +57,7 @@ "<handler to '" +| name |+ "' / " +| addr |+ ">" instance ToAddress (ContractHandle cp st vd) where- toAddress = chAddress+ toAddress = MkAddress . chAddress -- TODO [#577]: simplify this instance once fundep in ToTAddress is added instance (cp' ~ cp, vd ~ vd') => ToTAddress cp' vd' (ContractHandle cp st vd) where@@ -70,15 +76,59 @@ chNiceStorageEvi :: forall param st vd. ContractHandle param st vd -> Dict (T.StorageScope $ T.ToT st) chNiceStorageEvi ContractHandle{} = mapDict (niceStorageEvi @st) Dict +class ToContractAddress addr where+ toContractAddress :: addr -> ContractAddress++instance ToContractAddress ContractAddress where+ toContractAddress = id++instance ToContractAddress (ContractHandle cp st vd) where+ toContractAddress = chAddress++class ToL1Address addr where+ toL1Address :: addr -> L1Address++instance ToL1Address (L1TAddress cp vd) where+ toL1Address = unL1TAddress++instance ToL1Address L1Address where+ toL1Address = id++instance L1AddressKind kind => ToL1Address (KindedAddress kind) where+ toL1Address = MkConstrainedAddress++instance ToL1Address (ContractHandle cp st vd) where+ toL1Address = MkConstrainedAddress . chAddress++-- | Counterpart of 'TAddress' that contains 'L1Address' instead of 'Address'.+newtype L1TAddress cp vd = L1TAddress { unL1TAddress :: L1Address }++instance (cp ~ cp', vd ~ vd') => ToTAddress cp' vd' (L1TAddress cp vd) where+ toTAddress = toTAddress . toAddress . unL1TAddress++-- | Counterpart of 'ToTAddress' that converts to 'L1TAddress' rather than+-- 'TAddress'.+class (ToTAddress cp vd addr, ToL1Address addr)+ => ToL1TAddress cp vd addr where+ toL1TAddress :: addr -> L1TAddress cp vd+instance (ToTAddress cp vd addr, ToL1Address addr)+ => ToL1TAddress cp vd addr where+ toL1TAddress = L1TAddress . toL1Address++-- NB: We declare ToL1TAddress as a typeclass for two reasons:+-- one, it defines a constraint synonym, and two, if we were to define+-- toL1Address as a simple function, GHC would complain about+-- ToTAddress being redundant -- it's not though, it constrains the types.+ -- | Declares that @addr@ points to an entity with a storage. -- -- @addr@ may fix storage type or may not - in the latter case the caller -- has to specify the storage type explicitly via type annotation.-class ToAddress addr => ToStorageType st addr where+class ToContractAddress addr => ToStorageType st addr where -- | Pick proof of that storage type is valid. pickNiceStorage :: addr -> Dict (NiceStorage st) -instance NiceStorage st => ToStorageType st Address where+instance NiceStorage st => ToStorageType st ContractAddress where pickNiceStorage _ = Dict instance (st ~ st') => ToStorageType st' (ContractHandle cp st vd) where
src/Test/Cleveland/Tasty/Internal.hs view
@@ -1,6 +1,5 @@ -- SPDX-FileCopyrightText: 2021 Oxhead Alpha -- SPDX-License-Identifier: LicenseRef-MIT-OA-{-# LANGUAGE InstanceSigs #-} -- | This module is the internal implementation of "Test.Cleveland.Tasty". module Test.Cleveland.Tasty.Internal@@ -53,10 +52,10 @@ import Morley.Client (MorleyClientConfig(..), mceTezosClientL, mkMorleyClientEnv) import Morley.Client.TezosClient.Types (tceMbTezosClientDataDirL)-import Test.Cleveland.Internal.Client as Client- (ClientM, NetworkEnv(..), neMorleyClientEnvL, runClevelandT)+import Test.Cleveland.Internal.Abstract (NetworkEnv(..), neMorleyClientEnvL)+import Test.Cleveland.Internal.Client as Client (ClientM, runNetworkT) import Test.Cleveland.Internal.Exceptions (WithCallStack(WithCallStack))-import Test.Cleveland.Internal.Pure as Pure (PureM, runClevelandT, runEmulatedT)+import Test.Cleveland.Internal.Pure as Pure (PureM, runEmulatedT) import Test.Cleveland.Internal.Scenario import Test.Cleveland.Tasty.Internal.Options (ContextLinesOpt(..), DataDirOpt(..), EndpointOpt(..), MoneybagAliasOpt(..), PathOpt(..),@@ -80,11 +79,11 @@ -- -- If a 'TestTree' contains many tests scheduled to run on a real Tezos network, -- those tests will be run sequentially.-testScenario :: TestName -> (forall m. MonadFail m => Scenario m) -> TestTree-testScenario testName scenario' =+testScenario :: TestName -> (forall m. Scenario m) -> TestTree+testScenario testName scenario_ = testGroup testName- [ singleTest "On emulator" (RunOnEmulator scenario')- , singleTest onNetworkTag (RunOnNetwork scenario')+ [ singleTest "On emulator" (RunOnEmulator scenario_)+ , singleTest onNetworkTag (RunOnNetwork scenario_) ] -- | Create a tasty test case from an emulated 'Scenario'.@@ -92,29 +91,27 @@ -- This will create a test tree with 1 test, -- which will run the 'Scenario' on the "Morley.Michelson.Runtime" emulator. testScenarioOnEmulator :: TestName -> Scenario PureM -> TestTree-testScenarioOnEmulator testname scenario' =+testScenarioOnEmulator testname scenario_ = testGroup testname- [ singleTest "On emulator" (RunOnEmulator scenario') ]+ [ singleTest "On emulator" (RunOnEmulator scenario_) ] -- | Create a tasty test case from a 'Scenario'. -- -- This will create a test tree with 1 test, -- which will run the 'Scenario' on real Tezos network. testScenarioOnNetwork :: TestName -> Scenario ClientM -> TestTree-testScenarioOnNetwork testname scenario' =+testScenarioOnNetwork testname scenario_ = testGroup testname- [ singleTest onNetworkTag (RunOnNetwork scenario') ]+ [ singleTest onNetworkTag (RunOnNetwork scenario_) ] newtype RunOnEmulator = RunOnEmulator (Scenario PureM) instance IsTest RunOnEmulator where run :: OptionSet -> RunOnEmulator -> (Progress -> IO ()) -> IO Result- run opts (RunOnEmulator scenario') _ = do+ run opts (RunOnEmulator (ScenarioEmulated emulatedT)) _ = do let MoneybagAliasOpt moneybagAlias = lookupOption opts- io = case scenario' of- ScenarioCleveland s -> Pure.runClevelandT moneybagAlias s- ScenarioEmulated s -> Pure.runEmulatedT moneybagAlias s+ io = Pure.runEmulatedT moneybagAlias emulatedT (io $> testPassed "") `catch` printFormattedException opts testOptions = Tagged clevelandOptions@@ -123,11 +120,11 @@ instance IsTest RunOnNetwork where run :: OptionSet -> RunOnNetwork -> (Progress -> IO ()) -> IO Result- run opts (RunOnNetwork (ScenarioCleveland clevelandT)) _ = do+ run opts (RunOnNetwork (ScenarioNetwork clevelandT)) _ = do let tastyEnv = tastyEnvFromOpts opts useNetworkEnv tastyEnv $ \networkEnv -> do- let io = Client.runClevelandT networkEnv clevelandT+ let io = Client.runNetworkT networkEnv clevelandT (io $> testPassed "") `catch` printFormattedException opts -- If a 'RunOnNetwork' test is created somewhere in a suite,
src/Test/Cleveland/Tasty/Internal/Options.hs view
@@ -25,7 +25,7 @@ import Test.Tasty.Options as Tasty (IsOption(..), OptionDescription(Option), safeRead) import Morley.Client.Parser (baseUrlReader)-import Morley.Tezos.Address.Alias (Alias(..))+import Morley.Tezos.Address.Alias import Morley.Tezos.Crypto qualified as Crypto import Morley.Util.CLI (HasCLReader(getMetavar, getReader)) @@ -134,16 +134,16 @@ parseValue = mkParseValue (SecretKeyOpt . Just) optionCLParser = mkOptionParser (SecretKeyOpt . Just) Nothing -newtype MoneybagAliasOpt = MoneybagAliasOpt Alias+newtype MoneybagAliasOpt = MoneybagAliasOpt ImplicitAlias deriving stock (Show, Eq) instance IsOption MoneybagAliasOpt where- defaultValue = MoneybagAliasOpt $ Alias "moneybag"+ defaultValue = MoneybagAliasOpt $ ImplicitAlias "moneybag" optionName = "cleveland-moneybag-alias" optionHelp = "[Test.Cleveland] Alias of the account to be used to execute all transfers/originations " <> "(unless overriden with `withSender`) and fund new accounts (unless overriden with `withMoneybag`)."- parseValue = Just . MoneybagAliasOpt . Alias . fromString+ parseValue = Just . MoneybagAliasOpt . ImplicitAlias . fromString data RunModeOpt = RunAllMode
src/Test/Cleveland/Util.hs view
@@ -92,7 +92,7 @@ import Morley.Michelson.Doc (DocItem, docItemPosition) import Morley.Michelson.Typed (SingI, SomeConstrainedValue(..)) import Morley.Michelson.Typed qualified as T-import Morley.Tezos.Address (Address, parseAddressRaw)+import Morley.Tezos.Address import Test.Cleveland.Instances ()
test/TestSuite/Cleveland/AddressRevealing.hs view
@@ -15,6 +15,6 @@ test <- newAddress auto test2 <- newFreshAddress auto - transferMoney test 1000+ transfer test [tz|1000u|] comment "new key address is revealed"- withSender test $ transferMoney test2 1+ withSender test $ transfer test2 [tz|1u|]
+ test/TestSuite/Cleveland/BadAddressReuse.hs view
@@ -0,0 +1,21 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++module TestSuite.Cleveland.BadAddressReuse (test_badAddressReuse) where++import Lorentz qualified as L++import Test.Tasty (TestTree)++import Test.Cleveland+import TestSuite.Util++test_badAddressReuse :: TestTree+test_badAddressReuse =+ testScenario "Bad smart contract address reuse (#729 regression test)" $ scenario do+ _ <- originate "abcdefgh" () $ idContract @() @()++ addr <- newAddress "abcdefgh"++ target <- newAddress "target"+ withSender addr $ transfer target [L.tz|0.1|]
test/TestSuite/Cleveland/BalanceCheck.hs view
@@ -8,7 +8,7 @@ import Test.Tasty (TestTree) -import Morley.Tezos.Address (Address)+import Morley.Tezos.Address import Morley.Util.SizedList qualified as SL import Morley.Util.SizedList.Types import Test.Cleveland@@ -16,10 +16,10 @@ test_BalanceCheck :: TestTree test_BalanceCheck = testScenario "An address's balance can be checked" $ scenario do- test :: Address <- newFreshAddress auto+ test :: ImplicitAddress <- newFreshAddress auto comment "balance is updated after transfer"- transferMoney test 100+ transfer test [tz|100u|] getBalance test @@== 100 test_EmptyBalanceCheck :: TestTree@@ -28,5 +28,5 @@ test ::< dummy ::< Nil' <- traverse newFreshAddress $ SL.replicateT auto -- Doing something in order not to get "validating empty scenario" error- transferMoney dummy 1+ transfer dummy [tz|1u|] getBalance test @@== 0
test/TestSuite/Cleveland/BatchOperation.hs view
@@ -7,7 +7,7 @@ import Test.Tasty (TestTree) -import Morley.Tezos.Core (Mutez, mkMutez)+import Morley.Tezos.Core (mkMutez) import Morley.Util.SizedList qualified as SL import Test.Cleveland import Test.Cleveland.Lorentz.Consumer@@ -21,13 +21,13 @@ test1 <- newFreshAddress auto contract1 <- inBatch $ do- contract1 <- originateSimple "c" ([] :: [()]) contractConsumer- transferMoney test1 100+ contract1 <- originate "c" ([] :: [()]) contractConsumer+ transfer test1 [tz|100u|] return contract1 getBalance test1 @@== 100 - transferMoney contract1 200+ transfer contract1 [tz|200u|] getBalance contract1 @@== 200 @@ -35,16 +35,15 @@ addresses <- traverse newFreshAddress $ SL.replicateT @5 auto let balances = SL.generate $ \i -> unsafeMkMutez' $ (i + 1) * 100 - inBatch $ do- for_ (SL.zip addresses balances) $ uncurry transferMoney+ inBatch $ for_ (SL.zip addresses balances) $ uncurry transfer traverse getBalance addresses @@== balances , testScenario "Can return multiple values from a batch" $ scenario do (_contract1, _contract2) <- inBatch $ do- contract1 <- originateSimple "c1" ([] :: [Integer]) contractConsumer- contract2 <- originateSimple "c2" ([] :: [Integer]) contractConsumer+ contract1 <- originate "c1" ([] :: [Integer]) contractConsumer+ contract2 <- originate "c2" ([] :: [Integer]) contractConsumer return (contract1, contract2) return ()
test/TestSuite/Cleveland/BatchTransferCheck.hs view
@@ -23,8 +23,8 @@ comment "balance is updated after batch transfer" inBatch $ do- for_ [100, 200] $ transferMoney test1- transferMoney test2 300+ for_ [100 :: Mutez, 200] $ transfer test1+ transfer test2 [tz|300u|] return () traverse getBalance addrs @@== 300 :< 300 :< Nil@@ -56,12 +56,12 @@ test_BatchTransferLeapingCosts :: TestTree test_BatchTransferLeapingCosts = testScenario "Check fees evaluation correctness for leaping transfer costs" $ scenario do- contract <- originateSimple "contract" [] (leapingContract @L.MText)+ contract <- originate "contract" [] (leapingContract @L.MText) comment "Perform batch transfer, second transaction should have much \ \higher cost with respect to the first one" inBatch $- for_ ["a", "b"] $ call contract CallDefault+ for_ ["a", "b"] $ transfer contract . calling def comment "Sanity check on storage" getStorage contract @@==
test/TestSuite/Cleveland/BytesSigning.hs view
@@ -25,7 +25,7 @@ testScenario "Bytestrings can be signed" $ scenario do dummy :< signer :< Nil <- traverse newFreshAddress $ "user" :< "signer" :< Nil - helper <- originateSimple "helper" () checkSignatureContract+ helper <- originate "helper" () checkSignatureContract let bytes = "some bytestring" @@ -34,5 +34,5 @@ dummyPK <- getPublicKey dummy expectFailedWith [L.mt|Invalid signature|] $- call helper CallDefault (dummyPK, (sig, bytes))- call helper CallDefault (signerPK, (sig, bytes))+ transfer helper $ calling def (dummyPK, (sig, bytes))+ transfer helper $ calling def (signerPK, (sig, bytes))
test/TestSuite/Cleveland/CallStack.hs view
@@ -30,8 +30,8 @@ import Morley.Client (TezosClientError(EConnreset), mceClientEnvL, mceTezosClientL) import Morley.Client.TezosClient (tceEndpointUrlL) import Morley.Michelson.Typed (convertContract, untypeValue)-import Morley.Tezos.Address (ta)-import Morley.Util.Interpolate (lit)+import Morley.Tezos.Address+import Morley.Util.Interpolate (it, lit) import Morley.Util.SizedList.Types import Test.Cleveland import Test.Cleveland.Internal.Client (neMorleyClientEnvL)@@ -159,94 +159,63 @@ do void $ signBinary @ByteString "" invalidAddr - , testFailureIncludesCallStack "callstack points to originateUntyped"- [lit|- void $ originateUntyped UntypedOriginateData- { uodName = ""- , uodBalance = 0- , uodStorage = untypeValue $ toVal @Natural 3- , uodContract = convertContract $ toMichelsonContract @() @() idContract- }- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- |]- do- -- force a failure by using a storage of the wrong type- void $ originateUntyped UntypedOriginateData- { uodName = ""- , uodBalance = 0- , uodStorage = untypeValue $ toVal @Natural 3- , uodContract = convertContract $ toMichelsonContract @() @() idContract- }-- , testFailureIncludesCallStack "callstack points to originateUntypedSimple"+ , testFailureIncludesCallStack "callstack points to originate with untyped" [lit|- void $ originateUntypedSimple ""+ void $ originate "" (untypeValue $ toVal @Natural 3) (convertContract $ toMichelsonContract @() @() idContract) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |] do -- force a failure by using a storage of the wrong type- void $ originateUntypedSimple ""+ void $ originate "" (untypeValue $ toVal @Natural 3) (convertContract $ toMichelsonContract @() @() idContract) - , testFailureIncludesCallStack "callstack points to originate"+ , testFailureIncludesCallStack "callstack points to originate with lorentz" [lit|- void $ originate OriginateData- { odName = ""- , odBalance = maxBound- , odStorage = ()- , odContract = idContract @() @()- }- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+ void $ originate+ ""+ ()+ (idContract @() @())+ (maxBound :: Mutez)+ ^^^^^^^^^^^^^^^^^^^^ |] do -- force a failure by transfering `maxBound` mutez- void $ originate OriginateData- { odName = ""- , odBalance = maxBound- , odStorage = ()- , odContract = idContract @() @()- }+ void $ originate+ ""+ ()+ (idContract @() @())+ (maxBound :: Mutez) , testFailureIncludesCallStack "callstack points to transfer" [lit|- transfer TransferData- { tdTo = invalidAddr- , tdAmount = 0- , tdEntrypoint = DefEpName- , tdParameter = ()- }- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^+ transfer invalidAddr+ ^^^^^^^^^^^^^^^^^^^^ |] do -- force a failure by transfering from an unknown alias- transfer TransferData- { tdTo = invalidAddr- , tdAmount = 0- , tdEntrypoint = DefEpName- , tdParameter = ()- }+ transfer invalidAddr , testFailureIncludesCallStack "callstack points to transferMoney"- [lit|- transferMoney invalidAddr 1- ^^^^^^^^^^^^^^^^^^^^^^^^^^^+ [it|+ transfer invalidAddr [tz|1u|\&]+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |] do -- force a failure by transfering from an unknown address- transferMoney invalidAddr 1+ transfer invalidAddr [tz|1u|] & withSender invalidAddr , testFailureIncludesCallStack "callstack points to call" [lit|- call invalidTAddr CallDefault ()- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+ transfer invalidTAddr+ ^^^^^^^^^^^^^^^^^^^^^ |] do -- force a failure by transfering to an unknown address- call invalidTAddr CallDefault ()+ transfer invalidTAddr , testFailureIncludesCallStack "callstack points to inBatch for batched transfers" [lit|@@ -256,8 +225,8 @@ do -- force a failure by transfering to an unknown address inBatch $ do- call (TAddress @() invalidAddr) CallDefault ()- call (TAddress @() invalidAddr) CallDefault ()+ transfer invalidAddr+ transfer invalidAddr return () , testFailureIncludesCallStack "callstack points to importUntypedContract"@@ -327,8 +296,8 @@ ^^^^^^^^^^^^^^^^^^^^^^^^ |] do- addr <- originateSimple "" () contractFailWith1- err <- catchTransferFailure $ call addr CallDefault ()+ addr <- originate "" () contractFailWith1+ err <- catchTransferFailure $ transfer addr checkTransferFailure err $ failedWith (constant @Natural 2) , testGroup "expectTransferFailure" $@@ -356,8 +325,8 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |] do- addr <- originateSimple "" () contractFailWith1- call addr CallDefault ()+ addr <- originate "" () contractFailWith1+ transfer addr & expectTransferFailure (failedWith (constant @Natural 2)) ] @@ -411,27 +380,27 @@ , testFailureIncludesCallStack "callstack points to getStorage" [lit|- void $ getStorage @() invalidAddr- ^^^^^^^^^^^^^^^^^^^^^^^^^^+ void $ getStorage @() invalidContractAddr+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |] do- void $ getStorage @() invalidAddr+ void $ getStorage @() invalidContractAddr , testFailureIncludesCallStackOnEmulator "callstack points to getFullStorage on emulator" [lit|- void $ getFullStorage @() invalidAddr- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+ void $ getFullStorage @() invalidContractAddr+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |] do- void $ getFullStorage @() invalidAddr+ void $ getFullStorage @() invalidContractAddr , testFailureIncludesCallStackOnEmulator "callstack points to getSomeStorage on emulator" [lit|- void $ getSomeStorage invalidAddr- ^^^^^^^^^^^^^^^^^^^^^^^^^^+ void $ getSomeStorage invalidContractAddr+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |] do- void $ getSomeStorage invalidAddr+ void $ getSomeStorage invalidContractAddr , sabotageNetworkEnv $ testFailureIncludesCallStackOnNetwork "callstack points to getBigMapValueMaybe"@@ -504,8 +473,8 @@ void $ runCode RunCode { rcContract = L.defaultContract @() @() $ L.failUsing @MText "Contract should fail"- , rcStorage = NotRPC ()- , rcParameter = NotRPC ()+ , rcStorage = untypeValue $ toVal ()+ , rcParameter = untypeValue $ toVal () , rcAmount = 0 , rcBalance = 0 , rcSource = Nothing@@ -518,8 +487,8 @@ void $ runCode RunCode { rcContract = L.defaultContract @() @() $ L.failUsing @MText "Contract should fail"- , rcStorage = NotRPC ()- , rcParameter = NotRPC ()+ , rcStorage = untypeValue $ toVal ()+ , rcParameter = untypeValue $ toVal () , rcAmount = 0 , rcBalance = 0 , rcSource = Nothing@@ -529,16 +498,16 @@ , testFailureIncludesCallStackOnEmulator "when a branchout branch throws, the callstack points to the function inside the branch" [lit|- getStorage @() invalidAddr- ^^^^^^^^^^^^^^^^^^^^^^^^^^+ getStorage @() invalidContractAddr+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | In 'a' branch:- | Unknown address provided: tz1fsFpWk691ncq1xwS62dbotECB67B13gfC+ | Unknown address provided: KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye |] do branchout [ "a" ?- void $- getStorage @() invalidAddr+ getStorage @() invalidContractAddr ] , testFailureIncludesCallStackOnEmulator "when a branchout branch throws ANY exception, the exception raised is printed in a right way"@@ -558,16 +527,16 @@ , testFailureIncludesCallStackOnEmulator "when offshoot throws, the callstack points to the function inside offshoot" [lit|- getStorage @() invalidAddr- ^^^^^^^^^^^^^^^^^^^^^^^^^^+ getStorage @() invalidContractAddr+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | In 'a' branch:- | Unknown address provided: tz1fsFpWk691ncq1xwS62dbotECB67B13gfC+ | Unknown address provided: KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye |] do offshoot "a" $ void $- getStorage @() invalidAddr+ getStorage @() invalidContractAddr , testFailureIncludesCallStack "callstack points to failure" [lit|@@ -694,9 +663,11 @@ ] where+ invalidAlias :: ContractAlias invalidAlias = "UnknownAlias" invalidAddr = [ta|tz1fsFpWk691ncq1xwS62dbotECB67B13gfC|]- invalidTAddr = TAddress @() invalidAddr+ invalidContractAddr = ContractAddress $ mkContractHashHack "asdf"+ invalidTAddr = ContractHandle @() @() @() "asdf" invalidContractAddr test_callStack_property :: TestTree test_callStack_property =
test/TestSuite/Cleveland/ChainIdGet.hs view
@@ -22,8 +22,8 @@ test_ChainIdGet :: TestTree test_ChainIdGet = testScenario "ChainId is retrievable" $ scenario do- helperAddr <- originateSimple "helper" (#storage :! dummyChainId) checkChainIdContract+ helperAddr <- originate "helper" (#storage :! dummyChainId) checkChainIdContract chainId <- getChainId- call helperAddr CallDefault ()+ transfer helperAddr getStorage helperAddr @@== #storage :! chainId
test/TestSuite/Cleveland/ContractAllocation.hs view
@@ -7,7 +7,7 @@ import Test.Tasty (TestTree) -import Morley.Tezos.Address (Address)+import Morley.Tezos.Address import Morley.Util.Named import Test.Cleveland @@ -16,15 +16,8 @@ test_ContractAllocation :: TestTree test_ContractAllocation = testScenario "Contracts can be allocated and called" $ scenario do- addresses :: [Address] <- replicateM 10 $ newFreshAddress auto- let- od = OriginateData- { odName = "allocator"- , odStorage = #storage :! (take 570 $ cycle addresses)- , odBalance = 25- , odContract = allocatorContract- }-- allocatorAddr <- originate od+ addresses :: [Address] <- replicateM 10 $ toAddress <$> newFreshAddress auto+ let storage = #storage :! (take 570 $ cycle addresses)+ allocatorAddr <- originate "allocator" storage allocatorContract [tz|25micro|] - call allocatorAddr CallDefault (take 25 $ cycle addresses)+ transfer allocatorAddr $ calling def (take 25 $ cycle addresses)
test/TestSuite/Cleveland/DFS.hs view
@@ -10,7 +10,6 @@ import Lorentz.Address import Lorentz.Entrypoints import Morley.Michelson.Typed qualified as T-import Morley.Tezos.Core (Mutez) import Test.Cleveland import TestSuite.Util.Contracts (inContractsDir) @@ -51,16 +50,11 @@ -- balance [ testScenario "Operations are performed in DFS order" $ scenario do transferAllAddr <-- importContract (inContractsDir "transfer_all.tz")- >>= originateSimple @TransferAllParameter "transfer_all" () . noViews+ importContract @TransferAllParameter (inContractsDir "transfer_all.tz")+ >>= originate "transfer_all" () . noViews transferAllCallerAddr <-- importContract (inContractsDir "transfer_all_caller.tz")- >>= originateSimple @TransferAllCallerParameter "transfer_all_caller" () . noViews- transfer $ TransferData- { tdTo = transferAllAddr- , tdAmount = 100- , tdEntrypoint = ep "receiveXtz"- , tdParameter = ()- } -- transferAllAddr 100- call transferAllCallerAddr (Call @"CallCPS") (toTAddress transferAllAddr)+ importContract @TransferAllCallerParameter (inContractsDir "transfer_all_caller.tz")+ >>= originate "transfer_all_caller" () . noViews+ transfer transferAllAddr [tz|100u|] $ calling (ep @"ReceiveXtz") ()+ transfer transferAllCallerAddr $ calling (ep @"CallCPS") $ toTAddress transferAllAddr ]
+ test/TestSuite/Cleveland/EmitMachinery.hs view
@@ -0,0 +1,62 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++module TestSuite.Cleveland.EmitMachinery+ ( test_SimpleEmit+ , test_InferredEmit+ , test_MultipleEmit+ ) where++import Fmt (pretty)+import Test.Tasty (TestTree)++import Lorentz (Contract)+import Test.Cleveland+import Test.Cleveland.Lorentz (embedContract)+import TestSuite.Util.Contracts++test_SimpleEmit :: TestTree+test_SimpleEmit =+ testScenario "transferWithEmit works on simple emit" $ scenario do+ simpleEmit <- originate "simple_emit" () contract+ [ContractEvent{..}] <- transfer simpleEmit WithContractEvents $ calling def ()+ pretty cePayload @== ("Right \"right\" :: or (nat %int) (string %str)" :: Text)+ toAddress ceSource @== toAddress simpleEmit+ ceTag @== "notify_client"+ where+ contract :: Contract () () ()+ contract = $$(embedContract (inContractsDir "simple_emit.tz"))++test_InferredEmit :: TestTree+test_InferredEmit =+ testScenario " on WithContractEvents inferred emit" $ scenario do+ inferredEmit <- originate "inferred_emit" () contract+ [ContractEvent{..}] <- transfer inferredEmit WithContractEvents $ calling def ()+ pretty cePayload @== ("Right \"right\" :: or nat string" :: Text)+ toAddress ceSource @== toAddress inferredEmit+ ceTag @== ""+ where+ contract :: Contract () () ()+ contract = $$(embedContract (inContractsDir "inferred_emit.tz"))++test_MultipleEmit :: TestTree+test_MultipleEmit =+ testScenario "transferWithEmit works on multiple emit" $ scenario do+ multipleEmit <- originate "multiple_emit" () contract+ evs <- transfer multipleEmit WithContractEvents $ calling def ()+ length evs @== 4+ let expected =+ [("one", Just "Right \"right\" :: or nat string")+ ,("two", Just "Left 123 :: or nat string")+ ,("three", Just "False :: bool")+ ,("four", Nothing)]+ check ContractEvent{..} (tag, ty) = do+ pretty <$> cePayload @== (ty :: Maybe Text)+ toAddress ceSource @== toAddress multipleEmit+ ceTag @== tag+ -- events are CONS'ed in the contract and hence end up reversed;+ -- the expectation is reversed here to simplify reasoning a bit.+ zipWithM_ check evs $ reverse expected+ where+ contract :: Contract () () ()+ contract = $$(embedContract (inContractsDir "multiple_emit.tz"))
test/TestSuite/Cleveland/EmptyImplicitAddress.hs view
@@ -17,8 +17,8 @@ test_EmptyImplicitAddressCalls = testScenario "Calling a contract with empty implicit address fails" $ scenario do addr <- newFreshAddress auto- contract <- originateSimple "contract" () $ idContract @() @()- call contract CallDefault ()+ contract <- originate "contract" () $ idContract @() @()+ transfer contract (calling def ()) & withSender addr & shouldFailWithMessage "Empty implicit contract" @@ -27,6 +27,6 @@ testScenario "Transferring from empty implicit address fails" $ scenario do addr <- newFreshAddress auto recvr <- newAddress auto- transferMoney recvr 0+ transfer recvr [tz|0|] & withSender addr & shouldFailWithMessage "Empty implicit contract"
test/TestSuite/Cleveland/Emulated.hs view
@@ -23,7 +23,7 @@ , testScenarioOnEmulator "fails if any branch fails" $ scenarioEmulated do addr <- newAddress auto- let branchA = "a" ?- transferMoney addr 0+ let branchA = "a" ?- transfer addr [tz|0u|] let branchB = "b" ?- pass branchout [branchA, branchB] & expectTransferFailure emptyTransaction branchout [branchB, branchA] & expectTransferFailure emptyTransaction@@ -33,10 +33,10 @@ initialBalance <- getBalance test branchout [ "a" ?- do- transferMoney test 2+ transfer test [tz|2u|] getBalance test @@== initialBalance + 2 , "b" ?- do- transferMoney test 3+ transfer test [tz|3u|] getBalance test @@== initialBalance + 3 ] @@ -44,26 +44,26 @@ test <- newAddress auto initialBalance <- getBalance test branchout- [ "a" ?- transferMoney test 3 ]+ [ "a" ?- transfer test [tz|3u|] ] getBalance test @@== initialBalance , testScenarioOnEmulator "adds branch name to error" $ scenarioEmulated do branchout [ "<branch name>" ?- void $- signBytes "" (unsafe $ parseAddress "tz1Zpj6cNhkVkvksGtRTwTrgfCG3WP9eA5BM")+ signBytes "" [ta|tz1Zpj6cNhkVkvksGtRTwTrgfCG3WP9eA5BM|] ] & shouldFailWithMessage "<branch name>" ] , testGroup "offshoot" [ testScenarioOnEmulator "fails if inner scenario fails" $ scenarioEmulated do addr <- newAddress auto- offshoot "a" (transferMoney addr 0)+ offshoot "a" (transfer addr [tz|0u|]) & expectTransferFailure emptyTransaction , testScenarioOnEmulator "offshoot's effects are discarded" $ scenarioEmulated do test <- newAddress auto initialBalance <- getBalance test- offshoot "a" $ transferMoney test 1+ offshoot "a" $ transfer test [tz|1u|] getBalance test @@== initialBalance ] ]
+ test/TestSuite/Cleveland/ErrorMessages.hs view
@@ -0,0 +1,18 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++module TestSuite.Cleveland.ErrorMessages+ ( test_error_message_shows_contract_alias+ ) where++import Lorentz as L+import Test.Cleveland+import Test.Tasty (TestTree)+import TestSuite.Util (shouldFailWithMessage)++test_error_message_shows_contract_alias :: TestTree+test_error_message_shows_contract_alias =+ testScenarioOnEmulator "Error message shows contract alias" $ scenario do+ ch <- originate "my-contract-alias" () $ L.defaultContract @() @() $ L.car # L.failWith+ shouldFailWithMessage "(my-contract-alias) failed with: Unit" do+ transfer ch
test/TestSuite/Cleveland/ExpectFailure.hs view
@@ -21,13 +21,13 @@ import Morley.Micheline (toExpression) import Morley.Michelson.Runtime.GState (genesisAddress1)-import Morley.Tezos.Address (parseAddress)+import Morley.Tezos.Address (ConstrainedAddress(..), ta) import Morley.Tezos.Core (parseChainId) import Morley.Util.Interpolate (i) import Test.Cleveland import Test.Cleveland.Internal.Abstract- (ExpressionOrTypedValue(..), FailedInBranch(..), GenericTestError(..), TransferFailure(..),- TransferFailureReason(..))+ (AddressAndAlias(..), ExpressionOrTypedValue(..), FailedInBranch(..), GenericTestError(..),+ TransferFailure(..), TransferFailureReason(..)) import Test.Cleveland.Internal.Actions (TransferFailurePredicate(..)) import Test.Cleveland.Internal.Exceptions (WithCallStack(..)) import Test.Cleveland.Internal.Pure (emptyScenarioBranch)@@ -38,93 +38,81 @@ test_CatchExceptions = testScenario "catches exceptions" $ scenario do validAddr <- newAddress auto- contractAddr <- originate OriginateData- { odName = "test catchTransferFailure"- , odStorage = ()- , odBalance = 1- , odContract = defaultContract testContractCode- }+ contractAddr <- originate+ "test catchTransferFailure"+ ()+ (defaultContract testContractCode)+ [tz|1u|] let (testContractWithNumericErrors, errorTagMap) = useNumericErrors testContractCode- contractNumericAddr <- originate OriginateData- { odName = "test catchTransferFailure numeric errors"- , odStorage = ()- , odBalance = 1- , odContract = defaultContract testContractWithNumericErrors- }+ contractNumericAddr <- originate+ "test catchTransferFailure numeric errors"+ ()+ (defaultContract testContractWithNumericErrors)+ [tz|1u|] - attempt (call contractAddr (Call @"TriggerFailWith") ()) >>= \case+ attempt (transfer contractAddr $ calling (ep @"TriggerFailWith") ()) >>= \case Left err -> checkTransferFailure err $ failedWith (constant [mt|oops|]) Right _ -> failure "Expected contract to fail" catchTransferFailure $- call contractAddr (Call @"TriggerFailWith") ()+ transfer contractAddr $ calling (ep @"TriggerFailWith") () expectTransferFailure (failedWith (constant [mt|oops|])) $- call contractAddr (Call @"TriggerFailWith") ()+ transfer contractAddr $ calling (ep @"TriggerFailWith") () expectTransferFailure (failedWith (constant [mt|oops|]) && addressIs contractAddr) $- call contractAddr (Call @"TriggerFailWith") ()+ transfer contractAddr $ calling (ep @"TriggerFailWith") () expectFailedWith [mt|oops|] $- call contractAddr (Call @"TriggerFailWith") ()+ transfer contractAddr $ calling (ep @"TriggerFailWith") () expectError (VoidResult False) $- call contractAddr (Call @"VoidEP") (mkVoid True)+ transfer contractAddr $ calling (ep @"VoidEP") (mkVoid True) expectTransferFailure (failedWith $ constant (1 :: Natural, (2 :: Natural, 3 :: Natural))) $- call contractAddr (Call @"TriggerFailWithRightCombedPair") ()+ transfer contractAddr $ calling (ep @"TriggerFailWithRightCombedPair") () -- Check that string and bytes forms of 'chain_id' are equal if they are -- used as error argument. let c = fromRight (error "impossible") $ parseChainId "NetXUdfLh6Gm88t" expectTransferFailure (failedWith (constant @ChainId c)) $- call contractAddr (Call @"TriggerFailWithChainIdStr") ()+ transfer contractAddr $ calling (ep @"TriggerFailWithChainIdStr") () expectTransferFailure (failedWith (constant @ChainId c)) $- call contractAddr (Call @"TriggerFailWithChainIdBytes") ()+ transfer contractAddr $ calling (ep @"TriggerFailWithChainIdBytes") () expectCustomError #customError 1 $- call contractAddr (Call @"TriggerFailWithCustomError") ()+ transfer contractAddr $ calling (ep @"TriggerFailWithCustomError") () expectCustomError_ #customErrorUnit1 $- call contractAddr (Call @"TriggerFailWithCustomErrorUnit1") ()+ transfer contractAddr $ calling (ep @"TriggerFailWithCustomErrorUnit1") () expectCustomError_ #customErrorUnit2 $- call contractAddr (Call @"TriggerFailWithCustomErrorUnit2") ()+ transfer contractAddr $ calling (ep @"TriggerFailWithCustomErrorUnit2") () expectCustomErrorNoArg #customErrorNoArg $- call contractAddr (Call @"TriggerFailWithCustomErrorNoArg") ()+ transfer contractAddr $ calling (ep @"TriggerFailWithCustomErrorNoArg") () expectNumericError errorTagMap (VoidResult False) $- call contractNumericAddr (Call @"VoidEP") (mkVoid True)+ transfer contractNumericAddr $ calling (ep @"VoidEP") $ mkVoid True expectTransferFailure shiftOverflow $- call contractAddr (Call @"TriggerShiftOverflow") ()+ transfer contractAddr $ calling (ep @"TriggerShiftOverflow") () expectTransferFailure gasExhaustion $- call contractAddr (Call @"TriggerGasExhaustion") ()+ transfer contractAddr $ calling (ep @"TriggerGasExhaustion") () expectTransferFailure emptyTransaction $- transferMoney validAddr 0+ transfer validAddr [tz|0u|] expectTransferFailure badParameter $- transfer TransferData- { tdTo = contractAddr- , tdAmount = 0- , tdEntrypoint = ep "expectAddress"- , tdParameter = [mt|aa|]- }+ transfer contractAddr $ unsafeCalling #expectAddress [mt|aa|] expectTransferFailure badParameter $- transfer TransferData- { tdTo = contractAddr- , tdAmount = 0- , tdEntrypoint = ep "expectAddress"- , tdParameter = (1 :: Natural)- }+ transfer contractAddr $ unsafeCalling #expectAddress @Natural 1 -- check that an action throws one of many errors. let expectedErrs =@@ -132,7 +120,7 @@ failedWith (constant @MText "oops") || failedWith (customError #customError 1) - call contractAddr (Call @"TriggerFailWithCustomError") () &+ transfer contractAddr (calling (ep @"TriggerFailWithCustomError") ()) & expectTransferFailure expectedErrs test_FailsIfTheGivenActionDoesNotThrow :: TestTree@@ -150,7 +138,7 @@ FailedInBranch emptyScenarioBranch $ SomeException $ WithCallStack callStack $ SomeException $ FailedInBranch emptyScenarioBranch $ SomeException $- TransferFailure (unsafe $ parseAddress "tz1fsFpWk691ncq1xwS62dbotECB67B13gfC") BadParameter+ TransferFailure (AddressAndAlias (MkAddress [ta|tz1fsFpWk691ncq1xwS62dbotECB67B13gfC|]) Nothing) BadParameter res <- attempt @TransferFailure action @@ -314,12 +302,12 @@ impl_test_AndPredicate_succeeds_if_all_conditions_hold conv = testScenario "AndPredicate succeeds if all conditions hold" $ scenario do- let err = TransferFailure genesisAddress1 $ FailedWith (conv $ toVal @Integer 1) Nothing+ let err = TransferFailure (AddressAndAlias (toAddress genesisAddress1) Nothing) $ FailedWith (conv $ toVal @Integer 1) Nothing checkTransferFailure err $ failedWith (constant @Integer 1) && addressIs genesisAddress1 impl_test_OrPredicate_succeeds_if_any_condition_holds conv = testScenario "AndPredicate succeeds if any condition holds" $ scenario do- let err = TransferFailure genesisAddress1 $ FailedWith (conv $ toVal @Integer 1) Nothing+ let err = TransferFailure (AddressAndAlias (toAddress genesisAddress1) Nothing) $ FailedWith (conv $ toVal @Integer 1) Nothing checkTransferFailure err $ failedWith (constant @Integer 1) || failedWith (constant @Integer 2) ||@@ -327,7 +315,7 @@ impl_test_AndPredicate_fails_if_any_condition_fails conv = testScenario "AndPredicate succeeds if all conditions hold" $ scenario do- let err = TransferFailure genesisAddress1 $ FailedWith (conv $ toVal @Integer 1) Nothing+ let err = TransferFailure (AddressAndAlias (toAddress genesisAddress1) Nothing) $ FailedWith (conv $ toVal @Integer 1) Nothing checkTransferFailure err ( failedWith (constant @Integer 1) &&@@ -349,7 +337,7 @@ impl_test_OrPredicate_fails_if_all_conditions_fail conv = testScenario "AndPredicate succeeds if all conditions hold" $ scenario do- let err = TransferFailure genesisAddress1 $ FailedWith (conv $ toVal @Integer 1) Nothing+ let err = TransferFailure (AddressAndAlias (toAddress genesisAddress1) Nothing) $ FailedWith (conv $ toVal @Integer 1) Nothing checkTransferFailure err ( failedWith (constant @Integer 2) ||@@ -373,7 +361,7 @@ impl_test_checkTransferFailure_shows_only_failing_predicates conv = testScenario "checkTransferFailure shows only failing predicates" $ scenario do- let err = TransferFailure genesisAddress1 $ FailedWith (conv $ toVal @Integer 1) Nothing+ let err = TransferFailure (AddressAndAlias (toAddress genesisAddress1) Nothing) $ FailedWith (conv $ toVal @Integer 1) Nothing checkTransferFailure err ( (failedWith (constant @Integer 1) && failedWith (constant @Integer 2)) &&
test/TestSuite/Cleveland/FailureLogs.hs view
@@ -15,19 +15,19 @@ test_FailureLogs :: TestTree test_FailureLogs = testScenarioOnEmulator "Can get logs even on scenario failure" $ scenarioEmulated do- contractAddr <- originateSimple "test catchTransferFailure" () testContract+ contractAddr <- originate "test catchTransferFailure" () testContract (logs1, result1) <- fmap (first collectLogs) . getMorleyLogs $ try @_ @SomeException do- call contractAddr L.CallDefault 0- call contractAddr L.CallDefault 1+ transfer contractAddr $ calling def 0+ transfer contractAddr $ calling def 1 failure "some failure" assert (isLeft result1) "result1 should be Left" unMorleyLogs logs1 @== ["One", "Two", "Three", "Four", "One", "Two"] (logs2, result2) <- fmap (first collectLogs) . getMorleyLogs $ try @_ @SomeException do- call contractAddr L.CallDefault 0+ transfer contractAddr $ calling def 0 failure "some failure"- call contractAddr L.CallDefault 1+ transfer contractAddr $ calling def 1 assert (isLeft result2) "result2 should be Left" unMorleyLogs logs2 @== ["One", "Two", "Three", "Four"]
test/TestSuite/Cleveland/Import.hs view
@@ -15,7 +15,7 @@ import Test.Tasty (TestTree) -import Lorentz.Value (Address, Mutez)+import Lorentz.Value (Address) import Morley.Tezos.Address (ta) import Test.Cleveland import Test.Cleveland.Lorentz (embedContract, embedValue, importValue)@@ -23,19 +23,19 @@ test_Import :: [TestTree] test_Import = [ testScenario "Can embed a contract" $ scenario do- contract <- originateSimple "basic1" []+ contract <- originate "basic1" [] $$(embedContract @() @[Integer] @() "../../contracts/basic1.tz") - call contract CallDefault ()+ transfer contract ] test_Embed :: [TestTree] test_Embed = [ testScenario "Can embed a contract" $ scenario do contractCode <- importContract @() @[Integer] @() "../../contracts/basic1.tz"- contract <- originateSimple "basic1" [] contractCode+ contract <- originate "basic1" [] contractCode - call contract CallDefault ()+ transfer contract ] test_ImportInt :: [TestTree]@@ -59,7 +59,7 @@ [ testScenarioOnEmulator "Can import an address value" $ scenario do value <- runIO $ importValue @Address "./test/fixtures/addrValue.txt" - value @== [ta|tz1Se5MhFNJdPrur2iNwC3nCLvYzr1y9TsZp|]+ value @== toAddress [ta|tz1Se5MhFNJdPrur2iNwC3nCLvYzr1y9TsZp|] ] test_EmbedAddress :: [TestTree]@@ -67,7 +67,7 @@ [ testScenarioOnEmulator "Can embed an address value" $ scenario do let value = $$(embedValue @Address "./test/fixtures/addrValue.txt") - value @== [ta|tz1Se5MhFNJdPrur2iNwC3nCLvYzr1y9TsZp|]+ value @== toAddress [ta|tz1Se5MhFNJdPrur2iNwC3nCLvYzr1y9TsZp|] ] test_ImportMutez :: [TestTree]
+ test/TestSuite/Cleveland/NetworkCaps.hs view
@@ -0,0 +1,18 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++module TestSuite.Cleveland.NetworkCaps+ ( test_network_caps+ ) where++import Test.Tasty (TestTree)++import Morley.Client qualified as Client+import Test.Cleveland++test_network_caps :: TestTree+test_network_caps = testScenarioOnNetwork "Network scenario can get NetworkEnv" $ scenarioNetwork do+ env <- getMorleyClientEnv+ chainID <- getChainId+ chainID' <- runIO $ Client.runMorleyClientM env Client.getChainId+ chainID @== chainID'
test/TestSuite/Cleveland/NewAddressCheck.hs view
@@ -36,7 +36,7 @@ (toRemain, _) = balance `divModMutezInt` (5 :: Int) ?: error "Bad div" toSpend = balance - toRemain - transferMoney test2 toSpend+ transfer test2 toSpend & withSender test balance2 <- getBalance test
test/TestSuite/Cleveland/OperationReplay.hs view
@@ -16,16 +16,16 @@ test_replayTransfer_fails :: TestTree test_replayTransfer_fails = testScenarioOnEmulator "Transfer operation replay is prohibited" $ scenarioEmulated do- dummyAddress <- chAddress <$> originateSimple @() @() "dummy" () idContract+ dummyAddress <- toAddress . chAddress <$> originate "dummy" () (idContract @() @()) contract <- importContract @Address @() @() (contractsDir </> "replay_transfer.tz")- replayTransfer <- originateSimple "replayTransfer" () contract- call replayTransfer CallDefault dummyAddress+ replayTransfer <- originate "replayTransfer" () contract+ transfer replayTransfer (calling def dummyAddress) & shouldFailWithMessage "Operation replay attempt" test_replayOrigination_fails :: TestTree test_replayOrigination_fails = testScenarioOnEmulator "Origination operation replay is prohibited" $ scenarioEmulated do contract <- importContract @() @() @() (contractsDir </> "replay_origination.tz")- replayOrigination <- originateSimple "replayOrigination" () contract- call replayOrigination CallDefault ()+ replayOrigination <- originate "replayOrigination" () contract+ transfer replayOrigination & shouldFailWithMessage "Operation replay attempt"
test/TestSuite/Cleveland/PrettyFailWith.hs view
@@ -16,10 +16,10 @@ test_PrettyFailWith :: TestTree test_PrettyFailWith = testScenarioOnEmulator "FailWith shows its argument using human-readable representation" $ scenarioEmulated do addr <- newFreshAddress auto- transferMoney addr 1 -- need at least some money to call+ transfer addr [tz|1u|] -- need at least some money to call withSender addr do- cont <- originateSimple "failing" () failing- call cont CallDefault () &+ cont <- originate "failing" () failing+ transfer cont & shouldFailWithMessage (fmt $ "failed with: \"" +| addr |+ "\"") failing :: Contract () () ()
test/TestSuite/Cleveland/PublicKeyToAddress.hs view
@@ -14,6 +14,7 @@ import Unsafe qualified (fromJust) import Lorentz as L hiding (comment)+import Morley.Tezos.Address import Test.Cleveland import Test.Cleveland.Instances () import Test.Cleveland.Internal.Abstract (SpecificOrDefaultAlias(..))@@ -33,16 +34,13 @@ testProperty "The address is calculated correctly from the given public key" $ withTests 200 $ property $ do alias <- fromString <$> (forAll $ Gen.string (Range.linear 0 100) Gen.unicode)- testScenarioProps $ scenario $ scenario' alias--scenario' :: (MonadCleveland caps m) => Alias -> m ()-scenario' alias = do- c <- originateSimple @PublicKey @(Maybe Address) "publicKeyToAddress" Nothing publicKeyToAddress+ testScenarioProps $ scenario do+ c <- originate "publicKeyToAddress" Nothing publicKeyToAddress - addr1 <- newAddress $ SpecificAlias alias- addr1pk <- getPublicKey addr1+ addr1 <- newAddress $ SpecificAlias alias+ addr1pk <- getPublicKey addr1 - call c CallDefault addr1pk- addr2 <- Unsafe.fromJust <$> getStorage @(Maybe Address) c+ transfer c $ calling def addr1pk+ addr2 <- Unsafe.fromJust <$> getStorage @(Maybe Address) c - addr1 @== addr2+ MkAddress addr1 @== addr2
test/TestSuite/Cleveland/RefillableAddress.hs view
@@ -27,7 +27,7 @@ balanceSender <- getBalance refillableAddr withSender refillableAddr do- transferMoney receiver (balanceSender + 1000) -- obviously more than sender has+ transfer receiver (balanceSender + 1000) -- obviously more than sender has getBalance receiver @@== (balanceSender + 1000) , testScenario "A refillable address refills when transfer amount == balance - 1 μtz" $ scenario do@@ -37,7 +37,7 @@ balanceSender <- getBalance refillableAddr withSender refillableAddr do- transferMoney receiver (balanceSender - 1) -- also would fail without auto-refill, due to fees+ transfer receiver (balanceSender - 1) -- also would fail without auto-refill, due to fees -- NOTE: the test crashes currently when transfer amount = balance; it seems like a -- bug in the local chain code. Theoretically, this test should work either way. @@ -48,12 +48,7 @@ -- storage burn should be at least >= 1 XTZ due to the contract size -- however, since 'refillableAddr' has at least 0.5 XTZ after 'refillable' -- we also transfer 0.5 XTZ to the contract; this ensures we're overbudget.- void $ withSender refillableAddr $ originate $ OriginateData- { odName = "so_big"- , odBalance = 0.5e6- , odContract = soBigContract- , odStorage = ()- }+ void $ withSender refillableAddr $ originate "so_big" () soBigContract [tz|0.5|] ] test_AddressDoesntRefill :: [TestTree]@@ -72,17 +67,17 @@ nonRefillable ::< receiver ::< Nil' <- traverse newFreshAddress $ SL.replicateT auto -- needed to reveal `nonRefillable`- transferMoney nonRefillable 1+ transfer nonRefillable [tz|1u|] shouldFailWithMessage errorMsg $- withSender nonRefillable $ transferMoney receiver 100+ withSender nonRefillable $ transfer receiver [tz|100u|] test_RefillFailure :: TestTree test_RefillFailure = testScenario "Refill should succeed even if moneybag can't make the call" $ scenario do owner <- refillable $ newFreshAddress "owner"- transferMoney owner 400 -- a little more than revelation fee to avoid empty_implicit_contract- contract <- originateSimple @() @L.Address @() "contract" owner $ L.defaultContract $+ transfer owner [tz|400u|] -- a little more than revelation fee to avoid empty_implicit_contract+ contract <- originate "contract" (L.toAddress owner) $ L.defaultContract @() @L.Address $ L.cdr L.# L.dup L.# L.sender@@ -90,7 +85,7 @@ (L.nil L.# L.pair) (L.push @L.MText "Sender is not owner" L.# L.failWith) balance1 <- getBalance owner- withSender owner $ call contract CallDefault ()+ withSender owner $ transfer contract balance2 <- getBalance owner -- check that owner was in fact refilled checkCompares balance1 (<=) balance2
+ test/TestSuite/Cleveland/ResolveAddress.hs view
@@ -0,0 +1,28 @@+-- SPDX-FileCopyrightText: 2022 Oxhead Alpha+-- SPDX-License-Identifier: LicenseRef-MIT-OA++module TestSuite.Cleveland.ResolveAddress+ ( test_resolves_address_of_contract+ , test_resolves_address_of_implicit_account+ ) where++import Test.Tasty (TestTree)++import Test.Cleveland+import Test.Cleveland.Internal.Abstract (SpecificOrDefaultAlias(SpecificAlias))+import Test.Cleveland.Lorentz.Types (toContractAddress)+import TestSuite.Util (idContract)++test_resolves_address_of_contract :: TestTree+test_resolves_address_of_contract =+ testScenario "Resolves address of contract" $ scenario do+ let alias = "contract-test-1"+ expectedAddress <- toContractAddress <$> originate alias () (idContract @() @())+ resolveAddress alias @@== expectedAddress++test_resolves_address_of_implicit_account :: TestTree+test_resolves_address_of_implicit_account =+ testScenario "Resolves address of implicit account" $ scenario do+ let alias = "contract-test-1"+ expectedAddress <- newAddress $ SpecificAlias alias+ resolveAddress alias @@== expectedAddress
test/TestSuite/Cleveland/RunCode.hs view
@@ -4,12 +4,13 @@ -- Disable the warning generated by the `L.source` instruction. {-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} +{-# LANGUAGE OverloadedLists #-}+ module TestSuite.Cleveland.RunCode ( test_runs_code , test_emulator_state_is_not_modified , test_other_operations_are_not_executed- , test_handles_bigmap- , test_handles_bigmap_ids+ , test_handles_mix_of_bigmaps_and_bigmap_ids , test_env_vars_can_be_observed , test_can_observe_existing_onchain_contracts_and_accounts , test_self_address_does_not_exist_onchain@@ -23,7 +24,10 @@ import Lorentz qualified as L import Lorentz.Base import Lorentz.Value-import Morley.Michelson.Runtime.GState (gsAddressesL)+import Morley.Michelson.Runtime.GState (gsContractAddressesL)+import Morley.Michelson.Typed (untypeValue)+import Morley.Michelson.Untyped (Elt(..), Value'(..))+import Morley.Tezos.Address import Morley.Tezos.Core (Timestamp(..)) import Test.Cleveland import Test.Cleveland.Internal.Pure (psGState)@@ -34,8 +38,8 @@ testScenario "runs the given contract's code" $ scenario do runCode RunCode { rcContract = increment- , rcStorage = NotRPC 5- , rcParameter = NotRPC 3+ , rcStorage = untypeValue $ toVal @Integer 5+ , rcParameter = untypeValue $ toVal @Integer 3 , rcAmount = 0 , rcBalance = 0 , rcSource = Nothing@@ -55,8 +59,8 @@ before <- get runCode RunCode { rcContract = transferToSender- , rcStorage = NotRPC ()- , rcParameter = NotRPC ()+ , rcStorage = untypeValue $ toVal ()+ , rcParameter = untypeValue $ toVal () , rcAmount = 900 , rcBalance = 900 , rcSource = Nothing@@ -88,8 +92,8 @@ -- then the counter should only be increased to 1 and then stop. runCode RunCode { rcContract = unboundRecursion- , rcStorage = NotRPC 0- , rcParameter = NotRPC ()+ , rcStorage = untypeValue $ toVal @Integer 0+ , rcParameter = untypeValue $ toVal () , rcAmount = 0 , rcBalance = 0 , rcSource = Nothing@@ -97,7 +101,7 @@ , rcLevel = Nothing } @@== 1 where- -- | A contract that calls itself forever, increment the counter in its storage by 1 on every call.+ -- A contract that calls itself forever, increment the counter in its storage by 1 on every call. unboundRecursion :: Contract () Integer () unboundRecursion = L.defaultContract $ L.cdr@@ -109,36 +113,30 @@ # L.dip L.nil # L.cons # L.pair -test_handles_bigmap :: TestTree-test_handles_bigmap =- testScenario "handles bigmaps in parameter/storage" $ scenario do- (total, bigMapId) <- runCode RunCode- { rcContract = lookupBigMapKey- , rcStorage = NotRPC ((0, 0), one ("key", 50))- , rcParameter = NotRPC ("key", one ("key", 20))- , rcAmount = 0- , rcBalance = 0- , rcSource = Nothing- , rcNow = Nothing- , rcLevel = Nothing- }-- total @== (50, 20)- -- Check that the bigmap was not actually created on-chain.- getBigMapValueMaybe bigMapId "key" @@== Nothing--test_handles_bigmap_ids :: TestTree-test_handles_bigmap_ids =- testScenario "handles bigmap IDs in parameter/storage" $ scenario do+test_handles_mix_of_bigmaps_and_bigmap_ids :: TestTree+test_handles_mix_of_bigmaps_and_bigmap_ids =+ testScenario "handles a mix of bigmaps and bigmap IDs in parameter/storage" $ scenario do -- Originate a contract with a big_map in its storage -- in order to actually create a valid on-chain bigmap ID.- handle <- originateSimple @() @(BigMap MText Integer) @() "bigmap" (one ("key", 30)) idContract+ handle <- originate "bigmap" (one ("key", 20)) $ idContract @() @(BigMap MText Integer) bigMapId <- getStorage handle - (total, _) <- runCode RunCode+ (_, results) <- runCode RunCode { rcContract = lookupBigMapKey- , rcStorage = IsRPC ((0, 0), bigMapId)- , rcParameter = IsRPC ("key", bigMapId)+ , rcParameter =+ -- a list with a big_map ID and a big_map value+ ValueSeq+ [ untypeValue $ toVal bigMapId+ , ValueMap [Elt (ValueString "key") (ValueInt 30)]+ ]+ , rcStorage =+ ValuePair+ (ValueSeq+ [ untypeValue $ toVal bigMapId+ , ValueMap [Elt (ValueString "key") (ValueInt 40)]+ ]+ )+ (ValueNil) , rcAmount = 0 , rcBalance = 0 , rcSource = Nothing@@ -146,7 +144,7 @@ , rcLevel = Nothing } - total @== (30, 30)+ results @== [40, 20, 30, 20] test_env_vars_can_be_observed :: TestTree test_env_vars_can_be_observed =@@ -156,8 +154,8 @@ envVars <- withSender sender $ runCode RunCode { rcContract = readEnvVars- , rcStorage = NotRPC Nothing- , rcParameter = NotRPC ()+ , rcStorage = untypeValue $ toVal $ Nothing @EnvVars+ , rcParameter = untypeValue $ toVal () , rcAmount = 456 , rcBalance = 123 , rcSource = Just source@@ -168,8 +166,8 @@ envLevel envVars @== 29 envNow envVars @== Timestamp 8 getChainId @@== envChainId envVars- envSender envVars @== sender- envSource envVars @== source+ envSender envVars @== toAddress sender+ envSource envVars @== toAddress source envAmount envVars @== 456 envBalance envVars @== 123 where@@ -204,13 +202,7 @@ test_can_observe_existing_onchain_contracts_and_accounts :: TestTree test_can_observe_existing_onchain_contracts_and_accounts = testScenario "existing onchain contracts/acounts can be observed" $ scenario do- contractAddress <- toAddress <$> originate OriginateData- { odName = "contract"- , odBalance = 123- , odStorage = ()- , odContract = idContract @Integer @()- }-+ contractAddress <- toAddress <$> originate "contract" () (idContract @Integer @()) [tz|123u|] let checkContractExists :: Contract () (Maybe Address) () checkContractExists = L.defaultContract $@@ -224,8 +216,8 @@ runCode RunCode { rcContract = checkContractExists- , rcStorage = IsRPC Nothing- , rcParameter = IsRPC ()+ , rcStorage = untypeValue $ toVal $ Nothing @Address+ , rcParameter = untypeValue $ toVal () , rcAmount = 0 , rcBalance = 0 , rcSource = Nothing@@ -249,10 +241,10 @@ # L.assertSome @MText "Expected to find a contract with parameter `Integer`." # L.address # L.some # L.nil # L.pair - selfAddr <- runCode RunCode+ MkAddress selfAddr@ContractAddress{} <- runCode RunCode { rcContract = returnSelf- , rcStorage = IsRPC Nothing- , rcParameter = IsRPC 0+ , rcStorage = untypeValue $ toVal $ Nothing @Address+ , rcParameter = untypeValue $ toVal @Integer 0 , rcAmount = 0 , rcBalance = 0 , rcSource = Nothing@@ -260,41 +252,51 @@ , rcLevel = Nothing } >>= evalJust "Expected contract to return a `Some`" - emulatorState ^. gsAddressesL . at selfAddr @== Nothing+ emulatorState ^. gsContractAddressesL . at selfAddr @== Nothing ---------------------------------------------------------------------------- -- Helpers ---------------------------------------------------------------------------- --- | Looks up an integer in:------ * The big_map given in the parameter--- * The big_map in the storage+-- | This contracts has a list of big_maps in its storage, and takes an additional+-- list of big_maps in its parameter. ----- ... and stores both results in the storage.-lookupBigMapKey :: Contract (MText, BigMap MText Integer) ((Integer, Integer), BigMap MText Integer) ()+-- When called, it looks up the key "key" in all big_maps, and stores+-- all results in a @[Integer]@ in the storage.+lookupBigMapKey+ :: Contract [BigMap MText Integer]+ ([BigMap MText Integer], [Integer])+ () lookupBigMapKey = L.mkContractWith L.intactCompilationOptions $ L.mkContractCode $+ -- Unpair everything L.unpair- # L.dip L.cdr- # L.unpair- # L.stackType @'[MText, BigMap MText Integer, BigMap MText Integer]-- # L.dup- # L.dip L.swap- # L.stackType @'[MText, BigMap MText Integer, MText, BigMap MText Integer]+ # L.dip L.unpair+ # L.stackType @'[[BigMap MText Integer], [BigMap MText Integer], [Integer]] - -- Make a copy of the bigmap in the storage- # L.dupN @4- # L.dug @4- # L.stackType @'[MText, BigMap MText Integer, MText, BigMap MText Integer, BigMap MText Integer]+ -- Discard the `[Integer]` in the storage+ # L.dipN @2 L.drop+ # L.stackType @'[[BigMap MText Integer], [BigMap MText Integer]] - -- Retrieve keys- # L.get- # L.assertSome @MText "Expected Some, found None."- # L.dug @2- # L.get- # L.assertSome @MText "Expected Some, found None."+ -- Get the value at key "key" from all big_maps+ # L.nil @Integer+ # L.swap+ # getValues+ # L.stackType @'[[Integer], [BigMap MText Integer]]+ # L.swap+ # getValues+ # L.stackType @'[[Integer]] - # L.pair+ # L.nil # L.pair # L.nil @Operation # L.pair+ where+ -- Get the value at key "key" from all big_maps+ getValues :: [BigMap MText Integer] ': [Integer] ': s :-> [Integer] ': s+ getValues =+ L.iter+ (+ L.push @MText "key"+ # L.get+ # L.assertSome @MText "Expected Some, found None."+ # L.cons+ )
test/TestSuite/Cleveland/StorageCheck.hs view
@@ -22,7 +22,7 @@ import Morley.Michelson.Typed.AnnotatedValue import Test.Cleveland-import Test.Cleveland.Lorentz (embedContract)+import Test.Cleveland.Lorentz (ToContractAddress, embedContract) import TestSuite.Util (BigMapInStorage(..), idContract, saveInStorageContract) import TestSuite.Util.Contracts (contractsDir) @@ -39,7 +39,7 @@ test_GetStorage :: TestTree test_GetStorage = testScenario "getStorage returns the contract's storage" $ scenario do- addr <- originateSimple+ addr <- originate "save parameter in storage" (1 :: Natural) saveInStorageContract@@ -47,12 +47,7 @@ comment "checking initial storage" getStorage addr @@== 1 - transfer TransferData- { tdTo = addr- , tdAmount = 100- , tdEntrypoint = DefEpName- , tdParameter = 2 :: Natural- }+ transfer addr [tz|100u|] $ calling def 2 comment "storage is updated after transfer" getStorage addr @@== 2@@ -68,7 +63,7 @@ , (2, "b") ] }- addr <- originateSimple @() @Storage "test" initialStorage idContract+ addr <- originate "test" initialStorage $ idContract @() @Storage getFullStorage addr @@== initialStorage test_GetFullStorageConditional :: TestTree@@ -82,14 +77,14 @@ , (2, "b") ] }- addr <- originateSimple @() @Storage "test" initialStorage idContract+ addr <- originate "test" initialStorage $ idContract @() @Storage ifEmulation (getFullStorage addr @@== initialStorage) (_stField1RPC <$> getStorage addr @@== 23) test_GetSomeStorage :: TestTree test_GetSomeStorage = testScenario "getSomeStorage is consistent with getStorage" $ scenario do- addr <- originateSimple @() @Storage "test" (Storage 1 [(2, "a")]) idContract+ addr <- originate "test" (Storage 1 [(2, "a")]) $ idContract @() @Storage storage <- getStorage addr someStorage <- getSomeStorage addr @@ -100,25 +95,27 @@ [ testScenario "importUntypedContract" $ scenario do contract <- importUntypedContract $ contractsDir </> "big_map_in_storage.tz" let initialStorage = (one (101, 102), 103) :: (BigMap Integer Integer, Natural)- addr <- originateUntypedSimple "contract" (T.untypeValue $ T.toVal initialStorage) contract+ addr <- originate "contract" (T.untypeValue $ T.toVal initialStorage) contract checkAnnotationsArePreserved addr , testScenario "importContract" $ scenario do contract <- importContract @Integer @(BigMap Integer Integer, Natural) @() $ contractsDir </> "big_map_in_storage.tz" let initialStorage = (one (101, 102), 103)- originateSimple "contract" initialStorage contract >>= checkAnnotationsArePreserved+ originate "contract" initialStorage contract >>= checkAnnotationsArePreserved , testScenario "importContract with a user-defined storage" $ scenario do contract <- importContract @Integer @BigMapInStorage @() $ contractsDir </> "big_map_in_storage.tz" let initialStorage = BigMapInStorage (one (101, 102)) 103- addr <- originateSimple "contract" initialStorage contract+ addr <- originate "contract" initialStorage contract checkAnnotationsArePreserved addr , testScenario "embedContract" $ scenario do let contract = $$(embedContract @Integer @BigMapInStorage @() $ contractsDir </> "big_map_in_storage.tz") let initialStorage = BigMapInStorage (one (101, 102)) 103- addr <- originateSimple "contract" initialStorage contract+ addr <- originate "contract" initialStorage contract checkAnnotationsArePreserved addr ] where- checkAnnotationsArePreserved :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m ()+ checkAnnotationsArePreserved+ :: (HasCallStack, MonadCleveland caps m, ToContractAddress addr)+ => addr -> m () checkAnnotationsArePreserved addr = do storage <- getSomeStorage addr storage ^? field "field2" . castTo @Natural . value @== Just 103
test/TestSuite/Cleveland/StorageWithBigMaps.hs view
@@ -106,9 +106,9 @@ test_EMPTY_BIG_MAP = testScenario "EMPTY_BIG_MAP always creates a new ID" $ scenario do forM_ contracts \c -> do- addr <- originateSimple "contract" [("a", 1)] c+ addr <- originate "contract" [("a", 1)] c id0 <- getStorage addr- call addr CallDefault ()+ transfer addr unBigMapId <$> getStorage addr @@/= unBigMapId id0 where contracts :: [Contract () (BigMap MText Integer) ()]@@ -133,9 +133,9 @@ test_UPDATE :: TestTree test_UPDATE = testScenario "UPDATE never creates a new ID" $ scenario do- addr <- originateSimple "contract" [("12", 12)] updateBigMap+ addr <- originate "contract" [("12", 12)] updateBigMap id0 <- getStorage addr- call addr CallDefault ()+ transfer addr unBigMapId <$> getStorage addr @@== unBigMapId id0 where updateBigMap :: Contract () (BigMap MText Integer) ()@@ -163,10 +163,10 @@ -- This test is here as a means of documentation. testGroup "DUP" [ testScenario "BigMap ID may be reused when old BigMap is discarded" $ scenario do- addr <- originateSimple "contract" [("a", 1)] dupAndDiscardOld+ addr <- originate "contract" [("a", 1)] dupAndDiscardOld originalId <- getStorage addr- call addr CallDefault ()+ transfer addr dupId <- getStorage addr ifEmulation @()@@ -176,10 +176,10 @@ (do unBigMapId dupId @== unBigMapId originalId) , testScenario "A new BigMap ID is generated when the old BigMap is not discarded" $ scenario do- addr <- originateSimple "contract" ([("a", 1)], [("a", 1)]) dupAndKeepBoth+ addr <- originate "contract" ([("a", 1)], [("a", 1)]) dupAndKeepBoth (id0, _) <- getStorage addr- call addr CallDefault ()+ transfer addr (id1, dupId) <- getStorage addr -- The original bigmap's ID did not change@@ -224,9 +224,9 @@ -- Originate the contract. -- Call the contract twice, to make sure the BigMapCounter is incremented -- inbetween operations.- addr <- originateSimple "create-big-maps" bigMaps createBigMaps- call addr CallDefault bigMaps- call addr CallDefault bigMaps+ addr <- originate "create-big-maps" bigMaps createBigMaps+ transfer addr $ calling def bigMaps+ transfer addr $ calling def bigMaps finalStorage <- getStorage addr let bigMapIds = finalStorage ^.. biplate @_ @(BigMapId Natural Natural) . to unBigMapId@@ -247,14 +247,14 @@ test_GetBigMapValue :: TestTree test_GetBigMapValue = testScenario "getBigMapValue retrieves the correct value" $ scenario do- contract1 <- originateSimple @() @(BigMap Integer MText, BigMap Integer MText)+ contract1 <- originate "contract1" ([(1, "a"), (2, "b")], [(1, "c"), (2, "d")])- idContract- contract2 <- originateSimple @() @(BigMap Integer MText, BigMap Integer MText)+ $ idContract @() @(BigMap Integer MText, BigMap Integer MText)+ contract2 <- originate "contract1" ([(1, "e"), (2, "f")], [(1, "g"), (2, "h")])- idContract+ $ idContract @() @(BigMap Integer MText, BigMap Integer MText) (bigMap1, bigMap2) <- getStorage contract1 (bigMap3, bigMap4) <- getStorage contract2@@ -274,7 +274,7 @@ let bmList = sampleList ++ [(5, "d")] expectedSize = Unsafe.fromIntegral @Int @Natural $ length bmList- c <- originateSimple @() @(BigMap Integer MText) "contract" (mkBigMap bmList) idContract+ c <- originate "contract" (mkBigMap bmList) $ idContract @() @(BigMap Integer MText) bigMapId <- getStorage c bmSize <- getBigMapSize bigMapId@@ -285,7 +285,7 @@ test_getAllBigMapValues = testScenario "getAllBigMapValues retrieves the correct values" $ scenario do let bmValues = snd <$> sampleList- c <- originateSimple @() @(BigMap Integer MText) "contract" (mkBigMap sampleList) idContract+ c <- originate "contract" (mkBigMap sampleList) $ idContract @() @(BigMap Integer MText) bigMapId <- getStorage c vs <- getAllBigMapValues bigMapId@@ -295,10 +295,10 @@ test_getAllBigMapValues_ConsistentWith_getBigMapValue :: TestTree test_getAllBigMapValues_ConsistentWith_getBigMapValue = testScenario "results of 'getAllBigMapValues' and 'getBigMapValue' are consistent" $ scenario do- c <- originateSimple @() @(BigMap Integer MText)+ c <- originate "contract" (mkBigMap sampleList)- idContract+ $ idContract @() @(BigMap Integer MText) bigMapId <- getStorage c @@ -317,10 +317,10 @@ test_GetBigMapValueMaybe_InvalidKey :: TestTree test_GetBigMapValueMaybe_InvalidKey = testScenario "getBigMapValueMaybe returns 'Nothing' when key is invalid" $ scenario do- addr <- originateSimple @() @(BigMap Integer MText, BigMap Integer MText)+ addr <- originate "contract1" ([(1, "a"), (2, "b")], [(2, "c"), (3, "d")])- idContract+ $ idContract @() @(BigMap Integer MText, BigMap Integer MText) (bigMap1, bigMap2) <- getStorage addr @@ -330,16 +330,16 @@ test_ID_BecomesInvalid :: TestTree test_ID_BecomesInvalid = testScenario "big_map IDs become invalid once the big_map is removed from the storage" $ scenario do- addr <- originateSimple @(BigMap Integer MText)+ addr <- originate "contract1" [(1, "a")]- saveInStorageContract+ $ saveInStorageContract @(BigMap Integer MText) bigMapId <- getStorage addr getBigMapValueMaybe bigMapId 1 @@== Just "a" -- Replace the big_map in the contract's storage with a new big_map (with same contents).- call addr CallDefault [(1, "a")]+ transfer addr $ calling def [(1, "a")] -- The old big_map ID should now be invalid. getBigMapValueMaybe bigMapId 1 @@== Nothing
test/TestSuite/Cleveland/Tasty/Report.hs view
@@ -29,8 +29,8 @@ fmap checkResultDescription reportExamples checkResultDescription :: (TestName, EmulatedT PureM (), Text) -> TestTree-checkResultDescription (testName, scenario', expectedErr) =- runViaTastyOnEmulator testName (singleOption (ContextLinesOpt 1)) scenario' \tastyResult -> do+checkResultDescription (testName, scenario_, expectedErr) =+ runViaTastyOnEmulator testName (singleOption (ContextLinesOpt 1)) scenario_ \tastyResult -> do let -- Some error lines might have trailing whitespace, we can ignore it here. strippedErr =
test/TestSuite/Cleveland/Tasty/Report/Examples.hs view
@@ -222,8 +222,8 @@ CallStack (from HasCallStack): |] -unknownAddr :: Address-unknownAddr = unsafe $ parseAddress "tz1X59tp9P7sk8qdPwqqATVbURbN6o8sMZ7Z"+unknownAddr :: ImplicitAddress+unknownAddr = [ta|tz1X59tp9P7sk8qdPwqqATVbURbN6o8sMZ7Z|] reportExamples :: [(String, EmulatedT PureM (), Text)] reportExamples =
test/TestSuite/Cleveland/TransferCheck.hs view
@@ -17,61 +17,18 @@ test_TransferFromContract :: TestTree test_TransferFromContract = testGroup "Transfers from contract"- [ testScenarioOnEmulator "Forbid transfers to implicit accounts (#440)" $ scenarioEmulated do- testRevealContract morleyMessage- , testScenarioOnNetwork "Forbid transfers to implicit accounts (#440)" $ scenario do- testRevealContract rpcMessage-- , testScenarioOnEmulator "Forbid transfers to empty implicit accounts (#440)" $ scenario do- testEmptyImplicitAccount morleyMessage- , testScenarioOnNetwork "Forbid transfers to empty implicit accounts (#440)" $ scenario do- testEmptyImplicitAccount rpcMessage- , testScenario "Fails transfering 0tz to plain account" $ scenario+ [ testScenario "Fails transfering 0tz to plain account" $ scenario $ testZeroTransactionFails , testScenario "Success transfering 0tz to a contract" $ scenario $ testZeroTransactionSuccess , testScenario "Allow transferring 0ꜩ from TRANSFER_TOKENS (#440)" $ scenario testEmptyTransfer ] where- morleyMessage :: String- morleyMessage = "Global transaction of funds (200 μꜩ) from an originated contract"-- rpcMessage :: String- rpcMessage = "Contracts (rx) cannot be revealed"-- testRevealContract :: MonadCleveland caps m => String -> m ()- testRevealContract expectedErrorMsg = do- addr <- newAddress auto- contractAddr <- originateSimple @() @() "rx" () idContract-- comment "give some funds to the originated contract"- transferMoney contractAddr 200-- comment "fail when transferring from contract"- transferMoney addr 200- & withSender (toAddress contractAddr)- & shouldFailWithMessage expectedErrorMsg-- testEmptyImplicitAccount :: MonadCleveland caps m => String -> m ()- testEmptyImplicitAccount expectedErrorMsg = do- testAddr <- newFreshAddress auto- contractAddr <- originate OriginateData- { odName = "rx"- , odStorage = ()- , odBalance = 500- , odContract = idContract @() @()- }-- comment "fail when transferring from contract"- transferMoney testAddr 200- & withSender (toAddress contractAddr)- & shouldFailWithMessage expectedErrorMsg- testEmptyTransfer :: MonadCleveland caps m => m () testEmptyTransfer = do- addr1 <- originateSimple "test1" () zeroTransferContract- addr2 <- originateSimple "test2" () idContract- call addr1 L.CallDefault (toTAddress addr2)+ addr1 <- originate "test1" () zeroTransferContract+ addr2 <- originate "test2" () idContract+ transfer addr1 $ calling def (toTAddress addr2) zeroTransferContract :: L.Contract (L.TAddress () ()) () () zeroTransferContract = L.defaultContract $@@ -90,36 +47,16 @@ test_nonUnitParamToImplicitAccount_fails = testScenario "`transfer` fails when param for an implicit account is not Unit" $ scenario do addr <- newFreshAddress "alias"- transfer TransferData- { tdTo = addr- , tdAmount = 2- , tdEntrypoint = DefEpName- , tdParameter = (2 :: Natural)- }+ transfer addr [tz|2u|] (unsafeCalling def (2 :: Natural)) & shouldFailWithMessage "Bad contract parameter for: " testZeroTransactionFails :: MonadCleveland caps m => m () testZeroTransactionFails = do wallet <- newAddress "wallet"- let- transferData = TransferData- { tdTo = wallet- , tdAmount = 0- , tdEntrypoint = DefEpName- , tdParameter = ()- }-- expectTransferFailure emptyTransaction (transfer transferData)+ expectTransferFailure emptyTransaction (transfer wallet) testZeroTransactionSuccess :: MonadCleveland caps m => m () testZeroTransactionSuccess = do- address <- originateSimple @MText "test0tzContract" True idContract- let- transferData = TransferData- { tdTo = address- , tdAmount = 0- , tdEntrypoint = DefEpName- , tdParameter = "aaa" :: MText- }+ address <- originate "test0tzContract" True $ idContract @MText - transfer transferData+ transfer address $ calling def "aaa"
test/TestSuite/Cleveland/VotingPower.hs view
@@ -17,16 +17,16 @@ test_VotingPowers = [ testScenario "Can pick voting power of some address" $ scenario do contract- <- originateSimple "vp contract" 0+ <- originate "vp contract" 0 =<< importContract @KeyHash @Natural @() ("../../contracts/voting_power.tz") let keyHash = unsafe $ parseHash "tz1Yq4Hj9u2f9473wAKiFEm36Sp2GfB5aTGa"- call contract CallDefault keyHash+ transfer contract $ calling def keyHash getStorage contract @@== 0 , testScenarioOnEmulator "Can set voting powers in test scenario" $ scenarioEmulated do contract- <- originateSimple "vp contract" (0, 0)+ <- originate "vp contract" (0, 0) =<< importContract @KeyHash @(Natural, Natural) @() ("../../contracts/voting_powers.tz") comment "Setting custom voting powers to access them later"@@ -34,6 +34,6 @@ let keyHash2 = unsafe $ parseHash "tz1hvYBbHRJhT3dQ8bEjc34xm3rjJJmTcuqs" setVotingPowers (mkVotingPowers [(keyHash, 123), (keyHash2, 57)]) - call contract CallDefault keyHash+ transfer contract $ calling def keyHash getStorage contract @@== (123, 180) ]
test/TestSuite/Cleveland/WithMoneybag.hs view
@@ -13,7 +13,7 @@ test_withMoneybag = testScenario "withMoneybag overrides the funder of new accounts" $ scenario do newMoneybag <- newFreshAddress "newMoneybag"- transferMoney newMoneybag 4_e6+ transfer newMoneybag [tz|4|] -- At the end of this test, we want to check that `newAddress` transfers funds from "newMoneybag" to "testAccount". -- However, this will only happen if:
test/TestSuite/Cleveland/WithSender.hs view
@@ -19,12 +19,12 @@ user <- newAddress auto balance1 <- getBalance user- withSender user $ originateSimple @() @() "contract" () idContract+ withSender user $ originate "contract" () $ idContract @() @() balance2 <- getBalance user checkCompares balance2 (<) balance1 balance3 <- getBalance user- withSender user $ inBatch $ originateSimple @() @() "contract" () idContract+ withSender user $ inBatch $ originate "contract" () $ idContract @() @() balance4 <- getBalance user checkCompares balance4 (<) balance3 @@ -33,12 +33,12 @@ testScenario "Transfer is made from the sender's address" $ scenario do user <- newAddress auto - contract <- originateSimple "contract" [] saveSender+ contract <- originate "contract" [] saveSender withSender user do- transfer (TransferData contract 0 (ep "") ())- transferMoney contract 0- call contract CallDefault ()- inBatch $ call contract CallDefault ()+ transfer contract+ transfer contract [tz|0u|]+ transfer contract+ inBatch $ transfer contract - getStorage contract @@== replicate 4 user+ getStorage contract @@== toAddress <$> replicate 4 user