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
    choice Transfer : ContractId TransferProposal
      with newOwner: Party
      controller owner
      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.
    choice Archives
      : ()
      controller issuer
      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
    observer locker

    ensure amount > 0.0

    --Transfer can happen only if it is not locked
    choice Transfer : ContractId TransferProposal
      with newOwner: Party
      controller owner
      do
        assert (locker == owner)
        create TransferProposal
          with coin=this; newOwner

      --Lock can be done if owner decides to bring a locker on board
    choice Lock : ContractId LockableCoin
      with newLocker: Party
      controller owner
      do
        assert (newLocker /= owner)
        create this with locker = newLocker

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

Locking By State Diagram

Locking by State diagram showing that the transfer choice is actionable only if the LockableCoin is unlocked.

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.