Skip to content

Commit

Permalink
Quickstart enhancement (digital-asset#15651)
Browse files Browse the repository at this point in the history
  • Loading branch information
brianweir-da authored Nov 23, 2022
1 parent 28fc360 commit cbebd86
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 114 deletions.
4 changes: 3 additions & 1 deletion templates/quickstart-finance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ This project contains the source code used in the getting-started tutorials.

Before opening Visual Studio Code you should run `./get-dependencies.sh` (or `get-dependencies.bat` for Windows users) to download the required Daml packages.

You can then open Daml Studio by running `daml studio`, or build the project using `daml build`. To run the project, run `daml start` (which also builds the project).
You can then open Daml Studio by running `daml studio`, or build the project using `daml build`.

To run the project, run `daml start` (which also builds the project).
22 changes: 12 additions & 10 deletions templates/quickstart-finance/daml.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@ dependencies:
- daml-script
data-dependencies:
# INTERFACE DEPENDENCIES
- .lib/daml-finance-interface-holding-0.1.3.dar
- .lib/daml-finance-interface-instrument-base-0.1.3.dar
- .lib/daml-finance-interface-lifecycle-0.1.3.dar
- .lib/daml-finance-interface-settlement-0.1.3.dar
- .lib/daml-finance-interface-types-0.1.3.dar
- .lib/daml-finance-interface-account.dar
- .lib/daml-finance-interface-holding.dar
- .lib/daml-finance-interface-instrument-base.dar
- .lib/daml-finance-interface-lifecycle.dar
- .lib/daml-finance-interface-settlement.dar
- .lib/daml-finance-interface-types.dar
# IMPLEMENTATION DEPENDENCIES
- .lib/daml-finance-holding-0.1.3.dar
- .lib/daml-finance-instrument-base-0.1.3.dar
- .lib/daml-finance-lifecycle-0.1.3.dar
- .lib/daml-finance-refdata-0.1.3.dar
- .lib/daml-finance-settlement-0.1.3.dar
- .lib/daml-finance-account.dar
- .lib/daml-finance-data.dar
- .lib/daml-finance-holding.dar
- .lib/daml-finance-instrument-token.dar
- .lib/daml-finance-lifecycle.dar
- .lib/daml-finance-settlement.dar
start-navigator: no
build-options:
- --target=1.15
Expand Down
109 changes: 75 additions & 34 deletions templates/quickstart-finance/daml/Scripts/Lifecycling.daml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module Scripts.Lifecycling where

import DA.Date (toDateUTC)
import DA.Map (empty, fromList)
import DA.Set (singleton)
import DA.Map qualified as M (empty)
import DA.Set qualified as S (empty, fromList, singleton)
import Daml.Script

-- INTERFACE DEPENDENCIES --
Expand All @@ -16,13 +16,14 @@ import Daml.Finance.Interface.Settlement.Types (Allocation(..), Approval(..))
import Daml.Finance.Interface.Types.Common (Id(..))

-- IMPLEMENTATION DEPENDENCIES --
import Daml.Finance.Instrument.Base.Instrument (Instrument(..))
import Daml.Finance.Data.Time.DateClock (DateClock(..))
import Daml.Finance.Instrument.Token.Instrument (Instrument(..))
import Daml.Finance.Lifecycle.Event.Distribution qualified as Distribution (Event(..))
import Daml.Finance.Lifecycle.Rule.Claim qualified as Claim (Rule(..))
import Daml.Finance.Lifecycle.Rule.Distribution qualified as Distribution (Rule(..))
import Daml.Finance.RefData.Time.DateClock (DateClock(..), Unit(..))
import Daml.Finance.Lifecycle.Types (Unit(..))

import Scripts.Settlement (runSettlement)
import Scripts.Settlement (SettlementState(..), runSettlement)

-- | Test script that
-- 1. executes the `runSettlement` script
Expand All @@ -36,73 +37,84 @@ runLifecycling = do

-- Execute the `runSettlement` script.
-- Bob now holds 10 tokens in his account.
(alice, bank, bob, public, aliceAccount, bobAccount, usdInstrument, tokenInstrument, settlementFactoryCid, aliceHoldingCid, bobHoldingCid) <- runSettlement
SettlementState{alice
, bank
, bob
, public
, aliceAccount
, bobAccount
, usdInstrument
, tokenInstrument
, settlementFactoryCid
, aliceHoldingCid
, bobHoldingCid} <- runSettlement

-- The bank creates a new version of the token instrument (the "ex-distribution" version)
-- This is the version Bob will hold after claiming the effect further down below.
-- NEW_VERSION_BEGIN
let newTokenInstrument = tokenInstrument with version = "1"
now <- getTime
tokenInstrumentCid <- toInterfaceContractId @Instrument.I <$> submit bank do
createCmd Instrument
with
depository = bank
issuer = bank
id = tokenInstrument.id
description = "Instrument representing units of a generic token"
version = "1"
observers = empty
validAsOf = now
createCmd Instrument with
depository = bank
issuer = bank
id = tokenInstrument.id
description = "Instrument representing units of a generic token"
version = "1"
observers = M.empty
validAsOf = now
-- NEW_VERSION_END

-- Create clock
-- CREATE_CLOCK_BEGIN
let today = toDateUTC now
clockCid <- toInterfaceContractId <$> submit bank do
createCmd DateClock with
u = Unit $ toDateUTC now
providers = S.singleton bank
date = Unit $ toDateUTC now
id = Id "CLOCK"
provider = bank
observers = empty
description = show today
observers = S.empty
-- CREATE_CLOCK_END

-- Create lifecycle rules
-- LIFECYCLE_RULES_BEGIN
distributionRuleCid <- toInterfaceContractId @Lifecycle.I <$> submit bank do
createCmd Distribution.Rule with
provider = bank
observers = fromList [("Distribution", singleton $ singleton bob)]
providers = S.singleton bank
lifecycler = bank
observers = S.singleton bob
lifecycleClaimRuleCid <- toInterfaceContractId @Claim.I <$> submitMulti [bank, bob] [] do
createCmd Claim.Rule with
custodian = bank
owner = bob
claimers = singleton bob
settler = bob
factoryCid = settlementFactoryCid
providers = S.fromList [bank, bob]
claimers = S.singleton bob
settlers = S.singleton bob
settlementFactoryCid
netInstructions = False
-- LIFECYCLE_RULES_END

-- Create cash distribution event
-- CREATE_EVENT_BEGIN
distributionEventCid <- toInterfaceContractId @Event.I <$> submit bank do
createCmd Distribution.Event with
provider = bank
providers = S.singleton bank
id = Id "DISTRIBUTION"
description = "Profit distribution"
effectiveDate = toDateUTC now
targetInstrument = tokenInstrument
newInstrument = newTokenInstrument
perUnitDistribution = [Instrument.qty 0.02 usdInstrument]
observers = empty
observers = S.empty
-- CREATE_EVENT_END

-- Lifecycle distribution event
-- LIFECYCLE_EVENT_BEGIN
(_, [effectCid]) <- submit bank do
exerciseCmd distributionRuleCid Lifecycle.Evolve with
ruleName = "Distribution"
settler = bank
observableCids = []
eventCid = distributionEventCid
clockCid
timeObservableCid = clockCid
observableCids = []
-- LIFECYCLE_EVENT_END

-- Claim effect
Expand All @@ -112,18 +124,47 @@ runLifecycling = do
claimer = bob
holdingCids = [bobHoldingCid]
effectCid
let [instructionCid] = result.instructionCids
batchId = Id "DistributionSettlement"
let [bobInstructionCid, bankInstructionCid, couponInstructionCid] = result.instructionCids
-- CLAIM_EVENT_END

-- EFFECT_SETTLEMENT_BEGIN
-- Allocate instruction
instructionCid <- submit bank do exerciseCmd instructionCid Instruction.Allocate with allocation = CreditReceiver
(bobInstructionCid, _) <- submit bob do
exerciseCmd bobInstructionCid Instruction.Allocate with
actors = S.singleton bob
allocation = Pledge bobHoldingCid

(bankInstructionCid, _) <- submit bank do
exerciseCmd bankInstructionCid Instruction.Allocate with
actors = S.singleton bank
allocation = CreditReceiver

(couponInstructionCid, _) <- submit bank do
exerciseCmd couponInstructionCid Instruction.Allocate with
actors = S.singleton bank
allocation = CreditReceiver

-- Approve instruction
instructionCid <- submit bob do exerciseCmd instructionCid Instruction.Approve with approval = TakeDelivery bobAccount
bobInstructionCid <- submit bank do
exerciseCmd bobInstructionCid Instruction.Approve with
actors = S.singleton bank
approval = DebitSender

bankInstructionCid <- submit bob do
exerciseCmd bankInstructionCid Instruction.Approve with
actors = S.singleton bob
approval = TakeDelivery bobAccount

couponInstructionCid <- submit bob do
exerciseCmd couponInstructionCid Instruction.Approve with
actors = S.singleton bob
approval = TakeDelivery bobAccount

-- Settle batch
submitMulti [bob] [public] do exerciseCmd result.batchCid Batch.Settle
submitMulti [bob] [public] do
exerciseCmd result.batchCid Batch.Settle with
actors = S.singleton bob
-- EFFECT_SETTLEMENT_END

pure ()
70 changes: 57 additions & 13 deletions templates/quickstart-finance/daml/Scripts/Settlement.daml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Scripts.Settlement where

import DA.Map as M (empty)
import DA.Set as S (fromList)
import DA.Set as S (fromList, singleton)
import Daml.Script

-- INTERFACE DEPENDENCIES --
Expand All @@ -14,13 +14,29 @@ import Daml.Finance.Interface.Settlement.Types (Allocation(..), Approval(..))
import Daml.Finance.Interface.Types.Common (AccountKey, Id(..), InstrumentKey(..))

-- IMPLEMENTATION DEPENDENCIES --
import Daml.Finance.Instrument.Base.Instrument (Instrument(..))
import Daml.Finance.Instrument.Token.Instrument (Instrument(..))
import Daml.Finance.Settlement.Factory (Factory(..))

import Workflow.CreditAccount qualified as CreditAccount
import Workflow.DvP qualified as DvP

import Scripts.Transfer (runTransfer)
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
settlementFactoryCid : ContractId Factory.I
aliceHoldingCid : ContractId Holding.I
bobHoldingCid : ContractId Holding.I
deriving (Eq, Show)

-- | Test script that
-- 1. executes the `runTransfer` script
Expand All @@ -31,14 +47,27 @@ runSettlement : Script SettlementState
runSettlement = do

-- Execute the `runTransfer` script.
-- Bob now holds 1'000 USD in his account
(alice, bank, bob, public, aliceAccount, bobAccount, usdInstrument, holdingFactoryCid, bobHoldingCid) <- runTransfer
-- Bob now holds USD 1'000 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
tokenInstrument = InstrumentKey
with
issuer = bank
depository = bank
id = instrumentId
version = instrumentVersion

now <- getTime

Expand Down Expand Up @@ -70,6 +99,7 @@ runSettlement = do
with
provider = bank
observers = S.fromList [alice, bob]
custodian = bank
-- SETTLEMENT_FACTORY_END

-- Alice proposes an FX trade to Bob
Expand All @@ -92,32 +122,46 @@ runSettlement = do
-- Settle the DvP Trade

-- i. Bob allocates his asset, Alice approves by providing her account.
allocatedPaySettleInstructionCid <- submit bob do
(allocatedPaySettleInstructionCid, _) <- submit bob do
exerciseCmd paySettleInstructionCid Instruction.Allocate with
actors = S.singleton bob
allocation = Pledge $ coerceContractId 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
(allocatedRecSettleInstructionCid, _) <- submit alice do
exerciseCmd recSettleInstructionCid Instruction.Allocate with
actors = S.singleton alice
allocation = Pledge $ coerceContractId 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
exerciseCmd batchCid Batch.Settle with
actors = singleton bob
-- SETTLE_END

pure (alice, bank, bob, public, aliceAccount, bobAccount, usdInstrument, tokenInstrument, settlementFactoryCid, toInterfaceContractId aliceHoldingCid, toInterfaceContractId bobHoldingCid)

-- | Helper container used to transfer state from one script to another.
type SettlementState = (Party, Party, Party, Party, AccountKey, AccountKey, InstrumentKey, InstrumentKey, ContractId Factory.I, ContractId Holding.I, ContractId Holding.I)
pure $ SettlementState
with
alice
bank
bob
public
aliceAccount
bobAccount
usdInstrument
tokenInstrument
settlementFactoryCid
aliceHoldingCid = toInterfaceContractId aliceHoldingCid
bobHoldingCid = toInterfaceContractId bobHoldingCid
Loading

0 comments on commit cbebd86

Please sign in to comment.