packages feed

morley-upgradeable-0.3: src/Lorentz/Contracts/UpgradeableCounterSdu/V1.hs

-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ

{-# OPTIONS_GHC -Wno-orphans #-}

module Lorentz.Contracts.UpgradeableCounterSdu.V1
  ( counterContract
  , migration
  , counterUpgradeParameters
  , counterDoc

    -- * Internals
  , runGetCounterValue
  , runAdd
  , permImpl
  ) where

import Lorentz
import Prelude (Identity)

import Data.Constraint (Dict(..))

import Lorentz.Contracts.Upgradeable.Common
import Lorentz.Contracts.Upgradeable.StorageDriven
import Lorentz.Contracts.UpgradeableCounterSdu
import Lorentz.UStore

{-# ANN module ("HLint: ignore Reduce duplication" :: Text) #-}

data UStoreTemplate = UStoreTemplate
  { counterValue :: UStoreField Natural
  , epInc :: UStoreEntrypoint UStoreTemplate ()
  , epAdd :: UStoreEntrypoint UStoreTemplate Natural
  , epGetCounterValue :: UStoreEntrypoint UStoreTemplate (Void_ () Natural)
  } deriving stock (Eq, Generic)

instance UStoreTemplateHasDoc UStoreTemplate where
  ustoreTemplateDocName = "V1"
  ustoreTemplateDocDescription =
    "Template for version 1 of the contract."

type UStorage = UStore UStoreTemplate

type Interface = UStoreEpInterface UStoreTemplate

instance KnownContractVersion (CounterSduV 1) where
  type VerInterface (CounterSduV 1) = Interface
  type VerUStoreTemplate (CounterSduV 1) = UStoreTemplate
  type VerPermanent (CounterSduV 1) = Permanent

_checkInterface :: Dict $ Interface ~
  [ "epInc" ?: ()
  , "epAdd" ?: Natural
  , "epGetCounterValue" ?: Void_ () Natural
  ]
_checkInterface = Dict

runInc :: Entrypoint () UStorage
runInc = do
  drop @()
  ustoreGetField #counterValue
  push @Natural 1; add
  ustoreSetField #counterValue
  nil; pair

runAdd :: Entrypoint Natural UStorage
runAdd = do
  dip $ ustoreGetField #counterValue
  add
  ustoreSetField #counterValue
  nil; pair

runGetCounterValue :: Entrypoint (Void_ () Natural) UStorage
runGetCounterValue = void_ $ do
  drop @()
  ustoreGetField #counterValue
  dip drop

counterContract :: UContractRouter (CounterSduV 1)
counterContract = mkSduContract sduFallbackFail

permImpl :: PermanentImpl (CounterSduV 1)
permImpl = mkSmallPermanentImpl
  ( #cGetCounter /-> void_ $ do
      drop @(); ustoreToField #counterValue; int
  , #cGetNothing /-> absurd_
  )

mkStorage :: UStoreTemplate
mkStorage = UStoreTemplate
  { counterValue = UStoreField 0
  , epInc = mkUStoreEntrypoint runInc
  , epAdd = mkUStoreEntrypoint runAdd
  , epGetCounterValue = mkUStoreEntrypoint runGetCounterValue
  }

-- | This function migrates the storage from an empty one to UStorage,
--   i.e. it populates the empty BigMap with initial values for each field
--   and entrypoints.
--   The result is expected to adhere to V1.UStoreTemplate.
migration :: UStoreMigration () UStoreTemplate
migration = fillUStore mkStorage

counterUpgradeParameters :: EpwUpgradeParameters Identity (CounterSduV 0) (CounterSduV 1)
counterUpgradeParameters = EpwUpgradeParameters
  { upMigrationScripts = migrationToScriptI migration
  , upNewCode = counterContract
  , upNewPermCode = permImpl
  }


-- TODO: come up with a proper way to include documentation to the
-- storage-driven upgradeable contracts
counterDoc :: '[()] :-> '[()]
counterDoc =
  docGroup (DName "Upgradeable counter (SDU)") $ do
    contractGeneralDefault

    doc $ DDescription
      "Sample of storage-driven upgradeable contract."
    sduContractDoc
      (sduAddEntrypointDoc (Proxy @UpgradeableEntrypointsKind) mkStorage)
      permImpl