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
, requestor
, settlementFactoryCid
} <- runSetupInternalSettlement
The settlement factory is employed by a party, known as the requestor, to create a batch and instructions from a list of routed steps. In the scripts, the requestor 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 requestor do
exerciseCmd settlementFactoryCid Settlement.Instruct with
instructors = fromList [requestor]
settlers = singleton requestor
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 requestor finally settles the batch:
-- i. Alice allocates.
(instructionCid, _) <- submit alice do
exerciseCmd instructionCid Instruction.Allocate with
actors = S.singleton alice
allocation = Pledge $ toInterfaceContractId aliceHoldingCid
-- ii. Bob approves.
instructionCid <- submit bob do
exerciseCmd instructionCid Instruction.Approve with
actors = S.singleton bob
approval = TakeDelivery bobAccount
-- iii. Requestor executes the settlement.
[bobHoldingCid] <- submit requestor do
exerciseCmd batchCid Batch.Settle with
actors = singleton requestor
Note that this occurs without involving the Bank, and either Alice or Bob could also take the role as the requestor. 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 requestor do
exerciseCmd settlementFactoryCid Settlement.Instruct with
instructors = fromList [requestor]
settlers = fromList [requestor]
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 = S.singleton alice
allocation = Pledge $ toInterfaceContractId aliceHoldingCid
-- ii. Bob approves.
instructionCid2 <- submit bob do
exerciseCmd instructionCid2 Instruction.Approve with
actors = S.singleton bob
approval = TakeDelivery bobAccount
-- iii. Bank approves and allocates.
instructionCid1 <- submit bank do
exerciseCmd instructionCid1 Instruction.Approve with
actors = S.singleton bank
approval = DebitSender
(instructionCid2, _) <- submit bank do
exerciseCmd instructionCid2 Instruction.Allocate with
actors = S.singleton bank
allocation = CreditReceiver
-- iv. Requestor executes the settlement.
[bobHoldingCid] <- submit requestor do
exerciseCmd batchCid Batch.Settle with
actors = singleton requestor
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 requestor do
exerciseCmd settlementFactoryCid Settlement.Instruct with
instructors = fromList [requestor]
settlers = singleton requestor
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 = S.singleton alice
allocation = Pledge $ toInterfaceContractId aliceHoldingCid
-- ii. Bob approves.
instructionCid2 <- submit bob do
exerciseCmd instructionCid2 Instruction.Approve with
actors = S.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 = S.singleton charlie
approval = PassThroughTo (charlieAccount, instructionKey2)
instructionKey1 <- retrieveKey charlie instructionCid1
instructionCid2 <- submit charlie do
exerciseCmd instructionCid2 Instruction.Allocate with
actors = S.singleton charlie
allocation = PassThroughFrom (charlieAccount, instructionKey1)
-- iv. Requestor executes the settlement.
[bobHoldingCid] <- submit requestor do
exerciseCmd batchCid Batch.Settle with
actors = singleton requestor
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
andCreditReceiver
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.