Locking by state

The original Coin template is shown below. This is the basis on which to implement locking by state

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)

In its original form, all choices are actionable as long as the contract is active. Locking by State requires introducing fields to track state. This allows for the creation of an active contract in two possible states: locked or unlocked. A Daml modeler can selectively make certain choices actionable only if the contract is in unlocked state. This effectively makes the asset lockable.

The state can be stored in many ways. This example demonstrates how to create a LockableCoin through a party. Alternatively, you can add a lock contract to the asset contract, use a boolean flag or include lock activation and expiry terms as part of the template parameters.

Here are the changes we made to the original Coin contract to make it lockable.

  • Add a locker party to the template parameters.
  • Define the states.
    • if owner == locker, the coin is unlocked
    • if owner != locker, the coin is in a locked state
  • The contract state is checked on choices.
    • Transfer choice is only actionable if the coin is unlocked
    • Lock choice is only actionable if the coin is unlocked and a 3rd party locker is supplied
    • Unlock is available to the locker party only if the coin is locked
template LockableCoin 
  with
    owner: Party
    issuer: Party
    amount: Decimal
    locker: Party
  where
    signatory issuer
    signatory owner
   
    ensure amount > 0.0

    --Transfer can happen only if it is not locked
    controller owner can
      Transfer : ContractId TransferProposal
        with newOwner: Party
        do   
            assert (locker == owner)
            create TransferProposal
             with coin=this; newOwner 
             
      --Lock can be done if owner decides to bring a locker on board
      Lock : ContractId LockableCoin
        with newLocker: Party
        do   
          assert (newLocker /= owner)
          create this with locker = newLocker

    --Unlock only makes sense if the coin is in locked state
    controller locker can 
      Unlock 
        : ContractId LockableCoin
        do   
            assert (locker /= owner)
            create this with locker = owner 

Locking By State Diagram

../../../_images/lockingByStateChange.png

Trade-offs

  • It requires changes made to the original contract template. Furthermore you should need to change all choices intended to be locked.
  • If locking and unlocking terms (e.g. lock triggering event, expiry time, etc) need to be added to the template parameters to track the state change, the template can get overloaded.