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