da-syndication-finance-temp.../daml/Scripts/Settlement.daml

175 lines
5.9 KiB
Plaintext
Raw Normal View History

2023-05-08 20:09:16 +00:00
module Scripts.Settlement where
import DA.Map as M (empty)
import DA.Set as S (fromList, singleton)
import Daml.Script
-- INTERFACE DEPENDENCIES --
import Daml.Finance.Interface.Holding.Base qualified as Holding (I)
import Daml.Finance.Interface.Instrument.Base.Instrument qualified as Instrument (I)
import Daml.Finance.Interface.Settlement.Batch qualified as Batch (Settle(..))
import Daml.Finance.Interface.Settlement.Factory qualified as Settlement (F)
import Daml.Finance.Interface.Settlement.Instruction qualified as Instruction (Allocate(..), Approve(..))
import Daml.Finance.Interface.Settlement.RouteProvider qualified as RouteProvider (I)
import Daml.Finance.Interface.Settlement.Types (Allocation(..), Approval(..))
import Daml.Finance.Interface.Types.Common.Types (AccountKey, Id(..), InstrumentKey(..))
import Daml.Finance.Interface.Util.Common (qty)
-- IMPLEMENTATION DEPENDENCIES --
import Daml.Finance.Instrument.Token.Instrument (Instrument(..))
import Daml.Finance.Settlement.Factory (Factory(..))
import Daml.Finance.Settlement.RouteProvider.SingleCustodian (SingleCustodian(..))
import Workflow.CreditAccount qualified as CreditAccount
import Workflow.DvP qualified as DvP
import Scripts.Transfer (TransferState(..), runTransfer)
-- | Helper container used to transfer state from one script to another.
data SettlementState = SettlementState
with
alice : Party
bank : Party
bob : Party
public : Party
aliceAccount : AccountKey
bobAccount : AccountKey
usdInstrument : InstrumentKey
tokenInstrument : InstrumentKey
routeProviderCid : ContractId RouteProvider.I
settlementFactoryCid : ContractId Settlement.F
aliceHoldingCid : ContractId Holding.I
bobHoldingCid : ContractId Holding.I
deriving (Eq, Show)
-- | Test script that
-- 1. executes the `runTransfer` script
-- 2. creates a token instrument
-- 3. credits a token holding to Alice in her bank account
-- 4. atomically exchanges the token against the cash holding
runSettlement : Script SettlementState
runSettlement = do
-- Execute the `runTransfer` script. Bob now holds USD 1000 in his account.
TransferState{alice
, bank
, bob
, public
, aliceAccount
, bobAccount
, cashInstrument = usdInstrument
, holdingFactoryCid
, newHoldingCid = bobHoldingCid} <- runTransfer
-- Bank creates a token instrument
let
instrumentId = Id "TOKEN"
instrumentVersion = "0"
tokenInstrument = InstrumentKey with
issuer = bank
depository = bank
id = instrumentId
version = instrumentVersion
now <- getTime
tokenInstrumentCid <- toInterfaceContractId @Instrument.I <$> submit bank do
createCmd Instrument with
depository = bank
issuer = bank
id = instrumentId
version = instrumentVersion
description = "Instrument representing units of a generic token"
validAsOf = now
observers = empty
-- Credit Alice's account with a token holding
aliceRequestCid <- submit alice do
createCmd CreditAccount.Request with
account = aliceAccount
instrument = tokenInstrument
amount = 10.0
aliceHoldingCid <- submit bank do exerciseCmd aliceRequestCid CreditAccount.Accept
-- Setup a route provider
-- This is used transform settlement `Step`s into a `RoutedStep`s using a single custodian
-- ROUTE_PROVIDER_BEGIN
routeProviderCid <- toInterfaceContractId @RouteProvider.I <$> submit bank do
createCmd SingleCustodian with
provider = bank; observers = S.fromList [alice, bob] ; custodian = bank
-- ROUTE_PROVIDER_END
-- Setup a Settlement Factory facility
-- This is used to generate settlement instructions from a list of `RoutedStep`s
-- SETTLEMENT_FACTORY_BEGIN
settlementFactoryCid <- toInterfaceContractId @Settlement.F <$> submit bank do
createCmd Factory with
provider = bank
observers = S.fromList [alice, bob]
-- SETTLEMENT_FACTORY_END
-- Alice proposes an FX trade to Bob
-- DVP_PROPOSE_BEGIN
dvpProposalCid <- submit bob do
createCmd DvP.Proposal with
id = "xccy trade"
recQuantity = qty 10.0 tokenInstrument
payQuantity = qty 1000.0 usdInstrument
proposer = bob
counterparty = alice
routeProviderCid
settlementFactoryCid
-- DVP_PROPOSE_END
-- DVP_ACCEPT_BEGIN
(batchCid, recSettleInstructionCid, paySettleInstructionCid) <- submit alice do
exerciseCmd dvpProposalCid DvP.Accept
-- DVP_ACCEPT_END
-- Settle the DvP Trade
-- i. Bob allocates his asset, Alice approves by providing her account.
(allocatedPaySettleInstructionCid, _) <- submit bob do
exerciseCmd paySettleInstructionCid Instruction.Allocate with
actors = S.singleton bob
allocation = Pledge bobHoldingCid
approvedPaySettleInstructionCid <- submit alice do
exerciseCmd allocatedPaySettleInstructionCid Instruction.Approve with
actors = S.singleton alice
approval = TakeDelivery aliceAccount
-- ii. Alice allocates her asset, Bob approves by providing his account.
-- ALLOCATE_APPROVE_BEGIN
(allocatedRecSettleInstructionCid, _) <- submit alice do
exerciseCmd recSettleInstructionCid Instruction.Allocate with
actors = S.singleton alice
allocation = Pledge aliceHoldingCid
approvedRecSettleInstructionCid <- submit bob do
exerciseCmd allocatedRecSettleInstructionCid Instruction.Approve with
actors = S.singleton bob
approval = TakeDelivery bobAccount
-- ALLOCATE_APPROVE_END
-- iii. Bob executes the settlement.
-- SETTLE_BEGIN
[bobHoldingCid, aliceHoldingCid] <- submitMulti [bob] [public] do
exerciseCmd batchCid Batch.Settle with
actors = singleton bob
-- SETTLE_END
pure $ SettlementState with
alice
bank
bob
public
aliceAccount
bobAccount
usdInstrument
tokenInstrument
routeProviderCid
settlementFactoryCid
aliceHoldingCid = toInterfaceContractId aliceHoldingCid
bobHoldingCid = toInterfaceContractId bobHoldingCid