Locking by archiving¶
Pre-condition: there exists a contract that needs to be locked and unlocked. In this section, Coin is used as the original contract to demonstrate locking and unlocking.
template Coin
  with
    owner: Party
    issuer: Party
    amount: Decimal
    delegates : [Party]
  where
    signatory issuer, owner
    observer delegates
    controller owner can
      Transfer : ContractId TransferProposal
        with newOwner: Party
        do   
            create TransferProposal
             with coin=this; newOwner
    --a coin can only be archived by the issuer under the condition that the issuer is the owner of the coin. This ensures the issuer cannot archive coins at will.
    controller issuer can
      Archives
        : ()
        do assert (issuer == owner)
Archiving is a straightforward choice for locking because once a contract is archived, all choices on the contract become unavailable. Archiving can be done either through consuming choice or archiving contract.
Consuming choice¶
The steps below show how to use a consuming choice in the original contract to achieve locking:
- Add a consuming choice, Lock, to the Coin template that creates a LockedCoin.
- The controller party on the Lock may vary depending on business context. In this example, owner is a good choice.
- The parameters to this choice are also subject to business use case. Normally, it should have at least locking terms (eg. lock expiry time) and a party authorized to unlock.
      Lock : ContractId LockedCoin
        with maturity: Time; locker: Party
        do create LockedCoin with coin=this; maturity; locker
- Create a LockedCoin to represent Coin in the locked state. LockedCoin has the following characteristics, all in order to be able to recreate the original Coin: - The signatories are the same as the original contract.
- It has all data of Coin, either through having a Coin as a field, or by replicating all data of Coin.
- It has an Unlock choice to lift the lock.
 - template LockedCoin with coin: Coin maturity: Time locker: Party where signatory coin.issuer, coin.owner controller locker can Unlock : ContractId Coin do create coin 
 
Locking By Consuming Choice Diagram
Archiving contract¶
In the event that changing the original contract is not desirable and assuming the original contract already has an Archive choice, you can introduce another contract, CoinCommitment, to archive Coin and create LockedCoin.
- Examine the controller party and archiving logic in the Archives choice on the Coin contract. A coin can only be archived by the issuer under the condition that the issuer is the owner of the coin. This ensures the issuer cannot archive any coin at will.
    controller issuer can
      Archives
        : ()
        do assert (issuer == owner)
- Since we need to call the Archives choice from CoinCommitment, its signatory has to be Issuer.
template CoinCommitment
  with
    owner: Party
    issuer: Party
    amount: Decimal
   where
    signatory issuer
- The controller party and parameters on the Lock choice are the same as described in locking by consuming choice. The additional logic required is to transfer the asset to the issuer, and then explicitly call the Archive choice on the Coin contract.
- Once a Coin is archived, the Lock choice creates a LockedCoin that represents Coin in locked state.
    controller owner can
      nonconsuming LockCoin
        : ContractId LockedCoin
        with coinCid: ContractId Coin
             maturity: Time
             locker: Party
        do   
          inputCoin <- fetch coinCid
          assert (inputCoin.owner == owner && inputCoin.issuer == issuer && inputCoin.amount == amount )
          --the original coin firstly transferred to issuer and then archivaed
          prop <- exercise coinCid Transfer with newOwner = issuer
          do          
            id <- exercise prop AcceptTransfer
            exercise id Archives
          --create a lockedCoin to represent the coin in locked state 
          create LockedCoin with 
            coin=inputCoin with owner; issuer; amount
            maturity; locker
 
Locking By Archiving Contract Diagram
Trade-offs¶
This pattern achieves locking in a fairly straightforward way. However, there are some tradeoffs.
- Locking by archiving disables all choices on the original contract. Usually for consuming choices this is exactly what is required. But if a party needs to selectively lock only some choices, remaining active choices need to be replicated on the LockedCoin contract, which can lead to code duplication.
- The choices on the original contract need to be altered for the lock choice to be added. If this contract is shared across multiple participants, it will require agreement from all involved.