-- SPDX-FileCopyrightText: 2021 Oxhead Alpha -- SPDX-License-Identifier: LicenseRef-MIT-OA -- | Basic types for the test framework. module Test.Cleveland.Lorentz.Types ( ContractHandle (..) , L1TAddress (..) , ToContractAddress (..) , ToL1Address (..) , ToL1TAddress (..) , ToStorageType (..) , NiceParameter , NiceParameterFull , NiceStorage , NicePackedValue , NiceUnpackedValue , ToAddress , toAddress -- * Notes -- $noteTAddress ) where import Data.Constraint (Dict(..)) import Fmt (Buildable(..), (+|), (|+)) import Lorentz.Address import Lorentz.Constraints import Morley.Tezos.Address import Morley.Tezos.Address.Alias -- | Handle to a contract. -- -- This is what you get when originating a contract and that allows further -- operations with the contract within the test framework. -- -- Note that this is part of the testing framework and exists solely in Haskell -- world, so it has no 'T.IsoValue' and related instances and cannot be used in -- Lorentz code. data ContractHandle (cp :: Type) (st :: Type) (vd :: Type) = (NiceParameter cp, NiceStorage st, NiceViewsDescriptor vd) => ContractHandle { chContractName :: ContractAlias , chAddress :: ContractAddress } deriving stock instance Show (ContractHandle cp st vd) instance Buildable (ContractHandle cp st vd) where build (ContractHandle name addr) = "" instance ToAddress (ContractHandle cp st vd) where 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 toTAddress = toTAddress . toAddress instance ToContractRef arg (TAddress cp vd) => ToContractRef arg (ContractHandle cp st vd) where toContractRef = toContractRef . toTAddress @cp 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 = Constrained instance ToL1Address (ContractHandle cp st vd) where toL1Address = Constrained . 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 ToContractAddress addr => ToStorageType st addr where -- | Pick proof of that storage type is valid. pickNiceStorage :: addr -> Dict (NiceStorage st) instance NiceStorage st => ToStorageType st ContractAddress where pickNiceStorage _ = Dict instance (st ~ st') => ToStorageType st' (ContractHandle cp st vd) where pickNiceStorage ContractHandle{} = Dict {- $noteTAddress == A note on 'TAddress' instance for 'ToStorageType' 'TAddress' isn't intended to be a part of the Cleveland API. In the absolute majority of cases, if one is interested in both parameter and storage, then they should use 'ContractHandle', as the storage type needs to be known either way. If one isn't interested in storage, they presumably wouldn't call functions to get storage. Hence, this instance wouldn't be particularly useful. Legacy code using 'TAddress' instead of 'ContractHandle' should be preferably updated, if possible. If nothing else, 'toAddress' can be used as a stopgap measure. -}