morley-upgradeable-0.3: src/Lorentz/Contracts/UserUpgradeable/Migrations.hs
-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ
{-# OPTIONS_GHC -Wno-orphans #-}
-- | This module contains common functions and types related to user-defined
-- upgrades. It intentionally does not include mint- and burn-related
-- functionality because these should be handled by particular token
-- implementations (V2 and V1 correspondingly).
--
-- Note that the naming in this module is different from
-- Lorentz.Contracts.Upgradeable: by "migration" here we mean the process
-- of transferring the value from an old contract to the new one rather than
-- applying a transformation to storage.
module Lorentz.Contracts.UserUpgradeable.Migrations
( MigrationTarget
, callMigrationTarget
, initiateMigration
) where
import Lorentz
type MigrationTarget = FutureContract (Address, Natural)
type HasMigrationTarget storage =
storage `HasFieldsOfType` '["migrationTarget" := Maybe MigrationTarget]
type HasAdmin storage =
storage `HasFieldsOfType` '["admin" := Address]
-- | Migration is already in progress and cannot be initiated again.
type instance ErrorArg "alreadyMigrating" = ()
-- | Migration script has not been set.
type instance ErrorArg "nowhereToMigrate" = ()
-- | Specified contract (which keeps the new version of the code) does not exist
-- or does not have the specified entrypoint of type (Address, Natural)
type instance ErrorArg "migrationTargetDoesNotExist" = EpAddress
instance CustomErrorHasDoc "alreadyMigrating" where
customErrClass = ErrClassActionException
customErrDocMdCause =
"Migration is already in progress. \
\Raised in repeated attempt to initiate migration."
instance CustomErrorHasDoc "nowhereToMigrate" where
customErrClass = ErrClassActionException
customErrDocMdCause =
"Migration script has not been set. \
\Raised on attempt to initiate migration."
instance CustomErrorHasDoc "migrationTargetDoesNotExist" where
customErrClass = ErrClassActionException
customErrDocMdCause =
"Contract with specified address (to which we migrate) does \
\not exist or has unexpected parameter type"
-- | Starts a migration from an old version of a contract to a new one.
initiateMigration
:: forall storage. (HasAdmin storage, HasMigrationTarget storage)
=> '[MigrationTarget, storage] :-> '[([Operation], storage)]
initiateMigration = do
dip $ do ensureAdmin; ensureNotMigrated
some; setField #migrationTarget
nil; pair
where
ensureAdmin :: '[storage] :-> '[storage]
ensureAdmin = do
getField #admin
sender
if IsEq
then nop
else failCustom_ #senderIsNotAdmin
ensureNotMigrated :: '[storage] :-> '[storage]
ensureNotMigrated = do
getField #migrationTarget
if IsSome
then failCustom_ #alreadyMigrating
else nop
-- |Forges a call to the new version; the forged operation contans the
-- address of the sender, and the amount of tokens to mint.
callMigrationTarget
:: forall storage. HasMigrationTarget storage
=> '[Natural, storage] :-> '[([Operation], storage)]
callMigrationTarget = do
sender
pair
stackType @('[(Address, Natural), storage])
dip $ do
getField #migrationTarget
ifSome nop $ failCustom_ #nowhereToMigrate
dup
runFutureContract
if IsSome
then dip drop
else do
checkedCoerce_
failCustom #migrationTargetDoesNotExist
push (toMutez 0)
stackType @('[(Address, Natural), Mutez, ContractRef (Address, Natural), _])
transferTokens
stackType @('[Operation, storage])
dip nil; cons; pair