Internal Settlement

This tutorial builds upon the concepts introduced in the Settlement getting-started tutorial. Compared to our previous Enhanced Transfers tutorial, which demonstrated the “direct” transfer of a holding from sender to receiver (at a single custodian), it delves further into the settlement mechanism with a batch and related instructions. This process enables the adjustment of record books across multiple entities and instrument holdings simultaneously.

In this tutorial, we will limit the complexity by focusing on a single custodian and the transfer of a single instrument. The next tutorial will explore the broader scenario involving multiple custodians. Eager learners are encouraged to extend this tutorial and the following one by incorporating more than one instrument as an exercise.

Understanding Internal Settlement with Examples

To start, let us briefly revisit the settlement process which was explained in the Settlement section. A Batch consists of one or more Instructions. Each instruction signifies a RoutedStep, delineating the quantity of an instrument to be transferred from a sender to a receiver at a specific custodian. For an instruction to be prepared for settlement (or execution), the sender-side must furnish an Allocation, and the receiver-side must provide an Approval.

This tutorial will walk you through three example scripts for settling instructions at a single custodian: runWrappedTransferSettlement, runCreditDebitSettlement, and runPassThroughSettlement.

The allocation processes in these scripts involve methods to commit a pre-existing holding (Pledge), a newly created holding (CreditReceiver), and a holding received concurrently (PassThroughFrom).

The approval methods entail taking delivery of a holding to an account (TakeDelivery), immediately nullifying the holding (DebitSender), and passing the holding through (as allocation) to another instruction (PassThroughTo).

Each script kicks off with runSetupInternalSettlement which initiates parties, a cash instrument issued by the Central Bank, accounts for Alice, Bob, and Charlie at a Bank, and a settlement factory:

  SetupInternalSettlement
    { instrument
    ; bank
    ; alice
    ; aliceAccount
    ; aliceHoldingCid
    ; bob
    ; bobAccount
    ; charlie
    ; charlieAccount
    ; instructor
    ; settlementFactoryCid
    } <- runSetupInternalSettlement

The settlement factory is employed by a party, known as the instructor, to create a batch and instructions from a list of routed steps. In the scripts, the instructor is also responsible for settling the batch once all instructions have been allocated and approved.

Wrapped Transfer

The first example encapsulates a transfer from Alice to Bob, from our previous Enhanced Transfers tutorial, by creating a batch and a single instruction:

  let
    routedStep = RoutedStep with
      custodian = bank
      sender = alice
      receiver = bob
      quantity = qty 1000.0 instrument

  -- Generate settlement instructions from a list of `RoutedStep`s.
  (batchCid, [instructionCid]) <-
    submit instructor do
      exerciseCmd settlementFactoryCid SettlementFactory.Instruct with
        instructor -- This is equivalent to writing instructor = instructor
        consenters = mempty
        settlers = singleton instructor
        id = Id "1"
        description = "Transfer from Alice to Bob"
        contextId = None
        routedSteps = [routedStep]
        settlementTime = None -- i.e., immediate settlement

Here, Alice allocates by pledging a holding, Bob approves by taking delivery to his account at the Bank, and the instructor finally settles the batch:

  -- i. Alice allocates.
  (instructionCid, _) <- submit alice do
    exerciseCmd instructionCid Instruction.Allocate with
      actors = singleton alice
      allocation = Pledge $ toInterfaceContractId aliceHoldingCid

  -- ii. Bob approves.
  instructionCid <- submit bob do
    exerciseCmd instructionCid Instruction.Approve with
      actors = singleton bob
      approval = TakeDelivery bobAccount

  -- iii. Instructor executes the settlement.
  [bobHoldingCid] <- submit instructor do
    exerciseCmd batchCid Batch.Settle with
      actors = singleton instructor

Note that this occurs without involving the Bank, and either Alice or Bob could also take the role as the instructor. As a result of running this script, Alice’s holding is transferred to Bob.

Credit and Debit

An alternative approach to transfer the holding from Alice to Bob includes the Bank as an intermediary.

  let
    routedStep1 = RoutedStep with
      custodian = bank
      sender = alice
      receiver = bank
      quantity = qty 1000.0 instrument
    routedStep2 = routedStep1 with
      sender = bank
      receiver = bob

  -- Generate settlement instructions from a list of `RoutedStep`s.
  (batchCid, [instructionCid1, instructionCid2]) <-
    submit instructor do
      exerciseCmd settlementFactoryCid SettlementFactory.Instruct with
        instructor
        consenters = mempty
        settlers = singleton instructor
        id = Id "1"
        description = "Movement of holding from Alice to Bob through debit and credit"
        contextId = None
        routedSteps = [routedStep1, routedStep2]
        settlementTime = None -- i.e., immediate settlement

Similar to the previous scenario, Alice allocates by pledging a holding, and Bob approves by taking delivery to his account. However, in this case, the Bank plays an intermediary role by allocating and approving, debiting the sender and crediting the receiver, respectively:

  -- i. Alice allocates.
  (instructionCid1, _) <- submit alice do
    exerciseCmd instructionCid1 Instruction.Allocate with
      actors = singleton alice
      allocation = Pledge $ toInterfaceContractId aliceHoldingCid

  -- ii. Bob approves.
  instructionCid2 <- submit bob do
    exerciseCmd instructionCid2 Instruction.Approve with
      actors = singleton bob
      approval = TakeDelivery bobAccount

  -- iii. Bank approves and allocates.
  instructionCid1 <- submit bank do
    exerciseCmd instructionCid1 Instruction.Approve with
      actors = singleton bank
      approval = DebitSender
  (instructionCid2, _) <- submit bank do
    exerciseCmd instructionCid2 Instruction.Allocate with
      actors = singleton bank
      allocation = CreditReceiver

  -- iv. Instructor executes the settlement.
  [bobHoldingCid] <- submit instructor do
    exerciseCmd batchCid Batch.Settle with
      actors = singleton instructor

We could have made the Bank approve and allocate its instructions by taking delivery to an account it owns and pledging a holding where it acts as the custodian. However, this would require the creation of “dummy” accounts and holdings, which can be avoided using the DebitSender and CreditReceiver methods. These methods can only be used when the receiver (resp. the sender) corresponds to the custodian.

Pass Through

The final script of this tutorial demonstrates how holdings received as part of the same settlement process can be allocated to a subsequent instruction. We again use two instructions, instruction1 and instruction2, but now with Charlie as the intermediary:

  let
    routedStep1 = RoutedStep with
      custodian = bank
      sender = alice
      receiver = charlie
      quantity = qty 1000.0 instrument
    routedStep2 = routedStep1 with
      sender = charlie
      receiver = bob

  -- Generate settlement instructions from a list of `RoutedStep`s.
  (batchCid, [instructionCid1, instructionCid2]) <-
    submit instructor do
      exerciseCmd settlementFactoryCid SettlementFactory.Instruct with
        instructor
        consenters = mempty
        settlers = singleton instructor
        id = Id "1"
        description = "Transfer from Alice to Bob via Charlie"
        contextId = None
        routedSteps = [routedStep1, routedStep2]
        settlementTime = None -- i.e., immediate settlement

Like in the previous examples, Alice allocates by pledging a holding, and Bob approves by taking delivery to his account. The intermediary, Charlie, allocates using PassThroughTo (charlieAccount, instruction2) and approves with PassThroughFrom (charlieAccount, instruction1), essentially enabling the holding Charlie receives from Alice to pass-through to Bob:

  -- i. Alice allocates.
  (instructionCid1, _) <- submit alice do
    exerciseCmd instructionCid1 Instruction.Allocate with
      actors = singleton alice
      allocation = Pledge $ toInterfaceContractId aliceHoldingCid

  -- ii. Bob approves.
  instructionCid2 <- submit bob do
    exerciseCmd instructionCid2 Instruction.Approve with
      actors = singleton bob
      approval = TakeDelivery bobAccount

  -- iii. Charlie approves and allocates (with pass-through).
  instructionKey2 <- retrieveKey charlie instructionCid2
  instructionCid1 <- submit charlie do
    exerciseCmd instructionCid1 Instruction.Approve with
      actors = singleton charlie
      approval = PassThroughTo (charlieAccount, instructionKey2)
  instructionKey1 <- retrieveKey charlie instructionCid1
  instructionCid2 <- submit charlie do
    exerciseCmd instructionCid2 Instruction.Allocate with
      actors = singleton charlie
      allocation = PassThroughFrom (charlieAccount, instructionKey1)

  -- iv. Instructor executes the settlement.
  [bobHoldingCid] <- submit instructor do
    exerciseCmd batchCid Batch.Settle with
      actors = singleton instructor

The significant advantage of the pass-through method is that Charlie doesn’t need any holdings upfront as he’s at a net zero position for incoming and outgoing holdings in this settlement process.

Note that the Bank could have utilized the pass-through approach to achieve the same result in the previous script, but it would still require a “dummy” account.

Summary

By the end of this tutorial, you should have a good grasp on how to apply various allocation and approval methods to instructions. The key points are:

  • A custodian can utilize the DebitSender and CreditReceiver methods to bypass the need for “dummy” accounts and holdings when approving and allocating instructions, respectively.
  • A holding settled via an intermediary at the same custodian can be passed through, thus eliminating the requirement for the intermediary to possess the holding upfront.

In the forthcoming tutorial, we will delve into more complex settlement transactions involving a transfer across multiple custodians.