-- Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates.  All rights reserved. 
-- SPDX-License-Identifier: Apache-2.0


{-# LANGUAGE PartialTypeSignatures #-}


module LockingBySafekeeping where

import CoinIssuance
import Utilities
import DA.Time

data LockResult = LockResult {
  coinCid : ContractId Coin;
  lockCid : ContractId LockedCoinV2
}

template LockedCoinV2
  with
    coin: Coin
    maturity: Time
    locker: Party
  where
    signatory locker, coin.owner

    controller locker can
      UnlockV2
        : ContractId Coin
        with coinCid : ContractId Coin
        do   
          inputCoin <- fetch coinCid
          assert (inputCoin.owner == locker)
          tpCid <- exercise coinCid Transfer with newOwner = coin.owner
          exercise tpCid AcceptTransfer

    controller coin.owner can
      ClawbackV2
        : ContractId Coin
        with coinCid : ContractId Coin
        do   
          currTime <- getTime
          assert (currTime >= maturity)
          inputCoin <- fetch coinCid
          assert (inputCoin == coin with owner=locker)
          tpCid <- exercise coinCid Transfer with newOwner = coin.owner
          exercise tpCid AcceptTransfer

template LockRequest
  with
    locker: Party
    maturity: Time
    coin: Coin
  where
    signatory locker

    controller coin.owner can
      Accept : LockResult
        with coinCid : ContractId Coin
        do   
          inputCoin <- fetch coinCid
          assert (inputCoin == coin)
          tpCid <- exercise coinCid Transfer with newOwner = locker
          coinCid <- exercise tpCid AcceptTransfer
          lockCid <- create LockedCoinV2 with locker; maturity; coin
          return LockResult {coinCid; lockCid}


locking : Scenario (ContractId Coin)  -- test
locking =
  scenario do

    [issuer, owner, newOwner, locker] <- makePartiesFrom ["Bank", "Me", "You", "Custodian Bank"]

    now <- pass (days 0)

   --when coin is created, owner = locker.  it is unlocked
    coinId <- createCoin issuer owner 100.0

    coin <- issuer `submit` do fetch coinId
    lockRequestCid <- locker `submit` do
      create LockRequest with locker; maturity= (addRelTime now (days 2)); coin
    lockResult <- owner `submit` do exercise lockRequestCid Accept with coinCid = coinId

    --since it is locked and maturity time hasn't elapsed yet, owner cannot clawback
    owner `submitMustFail` do exercise lockResult.lockCid ClawbackV2 with coinCid = lockResult.coinCid

    --only after unlock, owner can access the coin
    unlockedCoin <- locker `submit` exercise lockResult.lockCid UnlockV2 with coinCid = lockResult.coinCid
    propId <- owner `submit` exercise unlockedCoin Transfer with newOwner
    newOwner `submit` exercise propId AcceptTransfer
