Initial commit
This commit is contained in:
commit
1e6d4aa792
10
README.md
Normal file
10
README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Code Samples - Getting Started
|
||||||
|
|
||||||
|
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).
|
53
daml.yaml
Normal file
53
daml.yaml
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# for config file options, refer to
|
||||||
|
# https://docs.daml.com/tools/assistant.html#project-config-file-daml-yaml
|
||||||
|
|
||||||
|
sdk-version: 2.6.3
|
||||||
|
name: tmp-finance-template
|
||||||
|
source: daml
|
||||||
|
init-script: Scripts.Transfer:runTransfer
|
||||||
|
version: 0.0.2
|
||||||
|
dependencies:
|
||||||
|
- daml-prim
|
||||||
|
- daml-stdlib
|
||||||
|
- daml-script
|
||||||
|
data-dependencies:
|
||||||
|
# INTERFACE DEPENDENCIES
|
||||||
|
- .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-common.dar
|
||||||
|
- .lib/daml-finance-interface-util.dar
|
||||||
|
# IMPLEMENTATION DEPENDENCIES
|
||||||
|
- .lib/daml-finance-account.dar
|
||||||
|
- .lib/daml-finance-holding.dar
|
||||||
|
- .lib/daml-finance-instrument-token.dar
|
||||||
|
- .lib/daml-finance-lifecycle.dar
|
||||||
|
- .lib/daml-finance-settlement.dar
|
||||||
|
# UNUSED INTERFACES DEPENDENCIES - UNCOMMENT TO ENABLE
|
||||||
|
# - .lib/daml-finance-interface-claims.dar
|
||||||
|
# - .lib/daml-finance-interface-data.dar
|
||||||
|
# - .lib/daml-finance-interface-instrument-bond.dar
|
||||||
|
# - .lib/daml-finance-interface-instrument-equity.dar
|
||||||
|
# - .lib/daml-finance-interface-instrument-generic.dar
|
||||||
|
# - .lib/daml-finance-interface-instrument-option.dar
|
||||||
|
# - .lib/daml-finance-interface-instrument-swap.dar
|
||||||
|
# - .lib/daml-finance-interface-instrument-token.dar
|
||||||
|
# - .lib/daml-finance-interface-types-date.dar
|
||||||
|
# UNUSED IMPLEMENTATIONS DEPENDENCIES - UNCOMMENT TO ENABLE
|
||||||
|
# - .lib/daml-finance-claims.dar
|
||||||
|
# - .lib/daml-finance-data.dar
|
||||||
|
# - .lib/daml-finance-instrument-bond.dar
|
||||||
|
# - .lib/daml-finance-instrument-equity.dar
|
||||||
|
# - .lib/daml-finance-instrument-generic.dar
|
||||||
|
# - .lib/daml-finance-instrument-option.dar
|
||||||
|
# - .lib/daml-finance-instrument-swap.dar
|
||||||
|
# - .lib/daml-finance-util.dar
|
||||||
|
# UNUSED CONTINGENT CLAIMS DEPENDENCIES - UNCOMMENT TO ENABLE
|
||||||
|
# - .lib/contingent-claims-core.dar
|
||||||
|
# - .lib/contingent-claims-lifecycle.dar
|
||||||
|
# - .lib/contingent-claims-valuation.dar
|
||||||
|
start-navigator: no
|
||||||
|
build-options:
|
||||||
|
- --target=1.15
|
158
daml/Scripts/Lifecycling.daml
Normal file
158
daml/Scripts/Lifecycling.daml
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
module Scripts.Lifecycling where
|
||||||
|
|
||||||
|
import DA.Map qualified as M (empty)
|
||||||
|
import DA.Set qualified as S (empty, fromList, singleton)
|
||||||
|
import Daml.Script
|
||||||
|
|
||||||
|
-- INTERFACE DEPENDENCIES --
|
||||||
|
import Daml.Finance.Interface.Instrument.Base.Instrument qualified as Instrument (I)
|
||||||
|
import Daml.Finance.Interface.Lifecycle.Event qualified as Event (I)
|
||||||
|
import Daml.Finance.Interface.Lifecycle.Rule.Claim qualified as Claim (ClaimEffect(..), I)
|
||||||
|
import Daml.Finance.Interface.Lifecycle.Rule.Lifecycle qualified as Lifecycle (Evolve(..), I)
|
||||||
|
import Daml.Finance.Interface.Settlement.Batch qualified as Batch (Settle(..))
|
||||||
|
import Daml.Finance.Interface.Settlement.Instruction qualified as Instruction (Allocate(..), Approve(..))
|
||||||
|
import Daml.Finance.Interface.Settlement.Types (Allocation(..), Approval(..))
|
||||||
|
import Daml.Finance.Interface.Types.Common.Types (Id(..))
|
||||||
|
import Daml.Finance.Interface.Util.Common (qty)
|
||||||
|
|
||||||
|
-- IMPLEMENTATION DEPENDENCIES --
|
||||||
|
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 Scripts.Settlement (SettlementState(..), runSettlement)
|
||||||
|
|
||||||
|
-- | Test script that
|
||||||
|
-- 1. executes the `runSettlement` script
|
||||||
|
-- 2. creates a distribution lifecycle rule
|
||||||
|
-- 3. creates a distribution lifecycle event
|
||||||
|
-- 4. lifecycles the distribution event
|
||||||
|
-- 5. processes the lifecycle effect
|
||||||
|
-- 6. settles the distribution
|
||||||
|
runLifecycling : Script()
|
||||||
|
runLifecycling = do
|
||||||
|
|
||||||
|
-- Execute the `runSettlement` script. Bob now holds 10 tokens in his account.
|
||||||
|
SettlementState{alice
|
||||||
|
, bank
|
||||||
|
, bob
|
||||||
|
, public
|
||||||
|
, aliceAccount
|
||||||
|
, bobAccount
|
||||||
|
, usdInstrument
|
||||||
|
, tokenInstrument
|
||||||
|
, routeProviderCid
|
||||||
|
, 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
|
||||||
|
version = "1"
|
||||||
|
description = "Instrument representing units of a generic token"
|
||||||
|
validAsOf = now
|
||||||
|
observers = M.empty
|
||||||
|
-- NEW_VERSION_END
|
||||||
|
|
||||||
|
-- Create lifecycle rules
|
||||||
|
-- LIFECYCLE_RULES_BEGIN
|
||||||
|
distributionRuleCid <- toInterfaceContractId @Lifecycle.I <$> submit bank do
|
||||||
|
createCmd Distribution.Rule with
|
||||||
|
providers = S.singleton bank
|
||||||
|
lifecycler = bank
|
||||||
|
observers = S.singleton bob
|
||||||
|
id = Id "Lifecycle rule for distribution"
|
||||||
|
description = "Rule contract to lifecycle an instrument following a distribution event"
|
||||||
|
|
||||||
|
lifecycleClaimRuleCid <- toInterfaceContractId @Claim.I <$> submitMulti [bank, bob] [] do
|
||||||
|
createCmd Claim.Rule with
|
||||||
|
providers = S.fromList [bank, bob]
|
||||||
|
claimers = S.singleton bob
|
||||||
|
settlers = S.singleton bob
|
||||||
|
routeProviderCid
|
||||||
|
settlementFactoryCid
|
||||||
|
netInstructions = False
|
||||||
|
-- LIFECYCLE_RULES_END
|
||||||
|
|
||||||
|
-- Create cash distribution event
|
||||||
|
-- CREATE_EVENT_BEGIN
|
||||||
|
distributionEventCid <- toInterfaceContractId @Event.I <$> submit bank do
|
||||||
|
createCmd Distribution.Event with
|
||||||
|
providers = S.singleton bank
|
||||||
|
id = Id "DISTRIBUTION"
|
||||||
|
description = "Profit distribution"
|
||||||
|
effectiveTime = now
|
||||||
|
targetInstrument = tokenInstrument
|
||||||
|
newInstrument = newTokenInstrument
|
||||||
|
perUnitDistribution = [qty 0.02 usdInstrument]
|
||||||
|
observers = S.empty
|
||||||
|
-- CREATE_EVENT_END
|
||||||
|
|
||||||
|
-- Lifecycle distribution event
|
||||||
|
-- LIFECYCLE_EVENT_BEGIN
|
||||||
|
(_, [effectCid]) <- submit bank do
|
||||||
|
exerciseCmd distributionRuleCid Lifecycle.Evolve with
|
||||||
|
eventCid = distributionEventCid
|
||||||
|
observableCids = []
|
||||||
|
instrument = tokenInstrument
|
||||||
|
-- LIFECYCLE_EVENT_END
|
||||||
|
|
||||||
|
-- Claim effect
|
||||||
|
-- CLAIM_EVENT_BEGIN
|
||||||
|
result <- submitMulti [bob] [public] do
|
||||||
|
exerciseCmd lifecycleClaimRuleCid Claim.ClaimEffect with
|
||||||
|
claimer = bob
|
||||||
|
holdingCids = [bobHoldingCid]
|
||||||
|
effectCid
|
||||||
|
batchId = Id "DistributionSettlement"
|
||||||
|
let [bobInstructionCid, bankInstructionCid, couponInstructionCid] = result.instructionCids
|
||||||
|
-- CLAIM_EVENT_END
|
||||||
|
|
||||||
|
-- EFFECT_SETTLEMENT_BEGIN
|
||||||
|
-- Allocate instruction
|
||||||
|
(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
|
||||||
|
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 with actors = S.singleton bob
|
||||||
|
-- EFFECT_SETTLEMENT_END
|
||||||
|
|
||||||
|
pure ()
|
5
daml/Scripts/README.md
Normal file
5
daml/Scripts/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Setup scripts
|
||||||
|
|
||||||
|
This folder includes setup scripts that are executed on a one-off basis.
|
||||||
|
|
||||||
|
Files in this folder can reference both interface and implementation packages of `daml-finance`.
|
174
daml/Scripts/Settlement.daml
Normal file
174
daml/Scripts/Settlement.daml
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
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
|
154
daml/Scripts/Transfer.daml
Normal file
154
daml/Scripts/Transfer.daml
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
module Scripts.Transfer where
|
||||||
|
|
||||||
|
import DA.Map (empty, fromList)
|
||||||
|
import DA.Set (singleton)
|
||||||
|
import Daml.Script
|
||||||
|
|
||||||
|
-- INTERFACE DEPENDENCIES --
|
||||||
|
import Daml.Finance.Interface.Account.Factory qualified as Account (F)
|
||||||
|
import Daml.Finance.Interface.Holding.Base qualified as Holding (I)
|
||||||
|
import Daml.Finance.Interface.Holding.Factory qualified as Holding (F)
|
||||||
|
import Daml.Finance.Interface.Instrument.Base.Instrument qualified as Instrument (I)
|
||||||
|
import Daml.Finance.Interface.Types.Common.Types (AccountKey, Id(..), InstrumentKey(..))
|
||||||
|
|
||||||
|
-- IMPLEMENTATION DEPENDENCIES --
|
||||||
|
import Daml.Finance.Account.Account qualified as Account (Factory(..))
|
||||||
|
import Daml.Finance.Holding.Fungible qualified as Fungible (Factory(..))
|
||||||
|
import Daml.Finance.Instrument.Token.Instrument (Instrument(..))
|
||||||
|
|
||||||
|
import Workflow.CreateAccount qualified as CreateAccount
|
||||||
|
import Workflow.CreditAccount qualified as CreditAccount
|
||||||
|
import Workflow.Transfer qualified as Transfer
|
||||||
|
|
||||||
|
-- | Helper container used to transfer state from one script to another.
|
||||||
|
data TransferState = TransferState
|
||||||
|
with
|
||||||
|
alice : Party
|
||||||
|
bank : Party
|
||||||
|
bob : Party
|
||||||
|
public : Party
|
||||||
|
aliceAccount : AccountKey
|
||||||
|
bobAccount : AccountKey
|
||||||
|
cashInstrument : InstrumentKey
|
||||||
|
holdingFactoryCid : ContractId Holding.F
|
||||||
|
newHoldingCid : ContractId Holding.I
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
-- | Test script that
|
||||||
|
-- 1. creates an account for Alice and Bob at the Bank
|
||||||
|
-- 2. issues a cash instrument
|
||||||
|
-- 3. credits a cash holding to Alice in her bank account
|
||||||
|
-- 4. transfers the holding from Alice to Bob
|
||||||
|
runTransfer : Script TransferState
|
||||||
|
runTransfer = do
|
||||||
|
|
||||||
|
-- Allocate parties
|
||||||
|
[alice, bank, bob, public] <- mapA createParty $ ["Alice", "Bank", "Bob", "Public"]
|
||||||
|
|
||||||
|
-- Account Factory (it is used by the bank to create accounts)
|
||||||
|
-- CREATE_ACCOUNT_FACTORY_BEGIN
|
||||||
|
accountFactoryCid <- toInterfaceContractId @Account.F <$> submit bank do
|
||||||
|
createCmd Account.Factory with provider = bank; observers = empty
|
||||||
|
-- CREATE_ACCOUNT_FACTORY_END
|
||||||
|
|
||||||
|
-- Holding Factory (it is used by the bank to create holdings with the desired implementation)
|
||||||
|
-- CREATE_HOLDING_FACTORY_BEGIN
|
||||||
|
holdingFactoryCid <- toInterfaceContractId @Holding.F <$> submit bank do
|
||||||
|
createCmd Fungible.Factory with
|
||||||
|
provider = bank
|
||||||
|
observers = fromList [("PublicObserver", singleton public )]
|
||||||
|
-- CREATE_HOLDING_FACTORY_END
|
||||||
|
|
||||||
|
-- Alice and Bob setup account @Bank
|
||||||
|
-- SETUP_ALICE_ACCOUNT_BEGIN
|
||||||
|
aliceRequestCid <- submit alice do
|
||||||
|
createCmd CreateAccount.Request with owner = alice; custodian = bank
|
||||||
|
aliceAccount <- submit bank do
|
||||||
|
exerciseCmd aliceRequestCid CreateAccount.Accept with
|
||||||
|
label = "Alice@Bank"
|
||||||
|
description = "Account of Alice at Bank"
|
||||||
|
accountFactoryCid = accountFactoryCid
|
||||||
|
holdingFactoryCid = holdingFactoryCid
|
||||||
|
observers = []
|
||||||
|
-- SETUP_ALICE_ACCOUNT_END
|
||||||
|
|
||||||
|
bobRequestCid <- submit bob do createCmd CreateAccount.Request with owner = bob; custodian = bank
|
||||||
|
bobAccount <- submit bank do
|
||||||
|
exerciseCmd bobRequestCid CreateAccount.Accept with
|
||||||
|
label = "Bob@Bank"
|
||||||
|
description = "Account of Bob at Bank"
|
||||||
|
accountFactoryCid = accountFactoryCid
|
||||||
|
holdingFactoryCid = holdingFactoryCid
|
||||||
|
observers = [alice]
|
||||||
|
|
||||||
|
-- Bank creates the cash instrument
|
||||||
|
-- ISSUE_CASH_INSTRUMENT_BEGIN
|
||||||
|
let
|
||||||
|
instrumentId = Id "USD"
|
||||||
|
instrumentVersion = "0"
|
||||||
|
now <- getTime
|
||||||
|
|
||||||
|
cashInstrumentCid <- toInterfaceContractId @Instrument.I <$> submit bank do
|
||||||
|
createCmd Instrument with
|
||||||
|
depository = bank
|
||||||
|
issuer = bank
|
||||||
|
id = instrumentId
|
||||||
|
version = instrumentVersion
|
||||||
|
description = "Instrument representing units of USD"
|
||||||
|
validAsOf = now
|
||||||
|
observers = empty
|
||||||
|
-- ISSUE_CASH_INSTRUMENT_END
|
||||||
|
|
||||||
|
-- Alice deposits cash at the bank
|
||||||
|
-- CREATE_ALICE_HOLDING_BEGIN
|
||||||
|
aliceRequestCid <- submit alice do
|
||||||
|
createCmd CreditAccount.Request with
|
||||||
|
account = aliceAccount
|
||||||
|
instrument = InstrumentKey with
|
||||||
|
issuer = bank
|
||||||
|
depository = bank
|
||||||
|
id = instrumentId
|
||||||
|
version = instrumentVersion
|
||||||
|
amount = 1000.0
|
||||||
|
|
||||||
|
aliceCashHoldingCid <- submit bank do exerciseCmd aliceRequestCid CreditAccount.Accept
|
||||||
|
-- CREATE_ALICE_HOLDING_END
|
||||||
|
|
||||||
|
-- Bob requests a cash transfer from Alice
|
||||||
|
-- TRANSFER_BEGIN
|
||||||
|
let
|
||||||
|
cashInstrument = InstrumentKey with
|
||||||
|
issuer = bank
|
||||||
|
depository = bank
|
||||||
|
id = instrumentId
|
||||||
|
version = instrumentVersion
|
||||||
|
|
||||||
|
transferRequestCid <- submit bob do
|
||||||
|
createCmd Transfer.Request with
|
||||||
|
receiverAccount = bobAccount
|
||||||
|
instrument = cashInstrument
|
||||||
|
amount = 1000.0
|
||||||
|
currentOwner = alice
|
||||||
|
|
||||||
|
newHoldingCid <- submitMulti [alice] [public] do
|
||||||
|
exerciseCmd transferRequestCid Transfer.Accept with holdingCid = aliceCashHoldingCid
|
||||||
|
-- TRANSFER_END
|
||||||
|
|
||||||
|
pure $ TransferState with
|
||||||
|
alice
|
||||||
|
bank
|
||||||
|
bob
|
||||||
|
public
|
||||||
|
aliceAccount
|
||||||
|
bobAccount
|
||||||
|
cashInstrument
|
||||||
|
holdingFactoryCid
|
||||||
|
newHoldingCid
|
||||||
|
|
||||||
|
-- | Creates a user + party given a hint
|
||||||
|
createParty : Text -> Script Party
|
||||||
|
createParty name = do
|
||||||
|
party <- allocatePartyWithHint name $ PartyIdHint name
|
||||||
|
userId <- validateUserId name
|
||||||
|
createUser (User userId (Some party)) [CanActAs party]
|
||||||
|
pure party
|
63
daml/Workflow/CreateAccount.daml
Normal file
63
daml/Workflow/CreateAccount.daml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
module Workflow.CreateAccount where
|
||||||
|
|
||||||
|
import DA.Map qualified as M (fromList)
|
||||||
|
import DA.Set qualified as S (fromList, singleton)
|
||||||
|
import Daml.Finance.Interface.Account.Account qualified as Account (Controllers(..))
|
||||||
|
import Daml.Finance.Interface.Account.Factory qualified as Account (Create(..), F)
|
||||||
|
import Daml.Finance.Interface.Holding.Factory qualified as Holding (F)
|
||||||
|
import Daml.Finance.Interface.Types.Common.Types (AccountKey(..), Id(..))
|
||||||
|
|
||||||
|
-- | Initiate / Accept template to open an account.
|
||||||
|
-- The account is created using an `Account.Factory` template. By doing so, our workflow is generic
|
||||||
|
-- and does not depend on the specific account implementation. For the same reason, we need to
|
||||||
|
-- provide a `Holding.Factory` that will be used by the account to create holdings without depending
|
||||||
|
-- on the specific implementation.
|
||||||
|
template Request
|
||||||
|
with
|
||||||
|
custodian : Party
|
||||||
|
-- ^ The account's custodian.
|
||||||
|
owner : Party
|
||||||
|
-- ^ The account's owner.
|
||||||
|
where
|
||||||
|
signatory owner
|
||||||
|
observer custodian
|
||||||
|
|
||||||
|
choice Accept : AccountKey
|
||||||
|
-- ^ Accept the request.
|
||||||
|
with
|
||||||
|
label : Text
|
||||||
|
-- ^ A textual label.
|
||||||
|
description : Text
|
||||||
|
-- ^ An extended textual description.
|
||||||
|
accountFactoryCid : ContractId Account.F
|
||||||
|
-- ^ The account factory. This is used to create the account template.
|
||||||
|
holdingFactoryCid : ContractId Holding.F
|
||||||
|
-- ^ The holding factory. This is used within an account to create holdings.
|
||||||
|
observers : [Party]
|
||||||
|
-- ^ Observers of the account to be created.
|
||||||
|
controller custodian
|
||||||
|
do
|
||||||
|
let
|
||||||
|
observersSet = S.fromList observers
|
||||||
|
accountKey = AccountKey with custodian = custodian, owner = owner, id = Id label
|
||||||
|
|
||||||
|
accountCid <- exercise accountFactoryCid Account.Create with
|
||||||
|
account = accountKey
|
||||||
|
description = description
|
||||||
|
holdingFactoryCid = holdingFactoryCid
|
||||||
|
controllers = Account.Controllers with
|
||||||
|
outgoing = S.singleton owner
|
||||||
|
incoming = S.singleton owner
|
||||||
|
observers = M.fromList [("AccountObservers", observersSet)]
|
||||||
|
|
||||||
|
pure accountKey
|
||||||
|
|
||||||
|
choice Decline : ()
|
||||||
|
-- ^ Decline the request.
|
||||||
|
controller custodian
|
||||||
|
do pure ()
|
||||||
|
|
||||||
|
choice Withdraw : ()
|
||||||
|
-- ^ Withdraw the request.
|
||||||
|
controller owner
|
||||||
|
do pure ()
|
40
daml/Workflow/CreditAccount.daml
Normal file
40
daml/Workflow/CreditAccount.daml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
module Workflow.CreditAccount where
|
||||||
|
|
||||||
|
import Daml.Finance.Interface.Account.Account qualified as Account (Credit(..), I, exerciseInterfaceByKey)
|
||||||
|
import Daml.Finance.Interface.Holding.Base qualified as Holding (I)
|
||||||
|
import Daml.Finance.Interface.Types.Common.Types (AccountKey(..), InstrumentKey)
|
||||||
|
import Daml.Finance.Interface.Util.Common (qty)
|
||||||
|
|
||||||
|
-- | Initiate / Accept template to credit a holding to an existing account.
|
||||||
|
template Request
|
||||||
|
with
|
||||||
|
account : AccountKey
|
||||||
|
-- ^ The account receiving the holding.
|
||||||
|
instrument : InstrumentKey
|
||||||
|
-- ^ The instrument to be credited.
|
||||||
|
amount : Decimal
|
||||||
|
-- ^ The number of units of the specified instrument to be credited.
|
||||||
|
where
|
||||||
|
signatory account.owner
|
||||||
|
observer account.custodian
|
||||||
|
|
||||||
|
ensure amount > 0.0
|
||||||
|
|
||||||
|
choice Accept : ContractId Holding.I
|
||||||
|
-- ^ Accept the request. In the case of physical assets (e.g. paper certificates, banknotes),
|
||||||
|
-- a custodian would generally accept the request once they have got hold of the physical
|
||||||
|
-- asset.
|
||||||
|
controller account.custodian
|
||||||
|
do
|
||||||
|
Account.exerciseInterfaceByKey @Account.I account account.custodian Account.Credit with
|
||||||
|
quantity = qty amount instrument
|
||||||
|
|
||||||
|
choice Decline : ()
|
||||||
|
-- ^ Decline the request.
|
||||||
|
controller account.custodian
|
||||||
|
do pure ()
|
||||||
|
|
||||||
|
choice Withdraw : ()
|
||||||
|
-- ^ Withdraw the request.
|
||||||
|
controller account.owner
|
||||||
|
do pure ()
|
73
daml/Workflow/DvP.daml
Normal file
73
daml/Workflow/DvP.daml
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
module Workflow.DvP where
|
||||||
|
|
||||||
|
import DA.Set (fromList, singleton)
|
||||||
|
import Daml.Finance.Interface.Settlement.Batch qualified as Batch (I)
|
||||||
|
import Daml.Finance.Interface.Settlement.Factory qualified as Settlement (F, Instruct(..))
|
||||||
|
import Daml.Finance.Interface.Settlement.Instruction qualified as Instruction (I)
|
||||||
|
import Daml.Finance.Interface.Settlement.RouteProvider qualified as RouteProvider (I, Discover(..))
|
||||||
|
import Daml.Finance.Interface.Settlement.Types (Step(..))
|
||||||
|
import Daml.Finance.Interface.Types.Common.Types (Id(..), InstrumentQuantity)
|
||||||
|
|
||||||
|
-- | Initiate / Accept template to exchange two holdings.
|
||||||
|
template Proposal
|
||||||
|
with
|
||||||
|
recQuantity : InstrumentQuantity
|
||||||
|
-- ^ The receiving leg (instrument and amount).
|
||||||
|
payQuantity : InstrumentQuantity
|
||||||
|
-- ^ The pay leg (instrument and amount).
|
||||||
|
proposer : Party
|
||||||
|
-- ^ The party proposing the trade. They receive the receiving leg in exchange for the pay
|
||||||
|
-- leg.
|
||||||
|
counterparty : Party
|
||||||
|
-- ^ The trade counterparty. They receive the pay leg in exchange for the receiving leg.
|
||||||
|
routeProviderCid : ContractId RouteProvider.I
|
||||||
|
-- ^ The route provider to discover settlement paths.
|
||||||
|
settlementFactoryCid : ContractId Settlement.F
|
||||||
|
-- ^ The factory contract for the settlement batch.
|
||||||
|
id : Text
|
||||||
|
-- ^ A textual identifier.
|
||||||
|
where
|
||||||
|
signatory proposer
|
||||||
|
observer counterparty
|
||||||
|
|
||||||
|
ensure recQuantity.amount > 0.0 && payQuantity.amount > 0.0
|
||||||
|
|
||||||
|
choice Accept : (ContractId Batch.I, ContractId Instruction.I, ContractId Instruction.I)
|
||||||
|
controller counterparty
|
||||||
|
do
|
||||||
|
let
|
||||||
|
-- Settlement of REC leg
|
||||||
|
recStep = Step with sender = counterparty; receiver = proposer; quantity = recQuantity
|
||||||
|
|
||||||
|
-- Settlement of PAY leg
|
||||||
|
payStep = Step with sender = proposer; receiver = counterparty; quantity = payQuantity
|
||||||
|
|
||||||
|
-- Discover settlement routes for the steps
|
||||||
|
routedSteps <- exercise routeProviderCid RouteProvider.Discover with
|
||||||
|
discoverors = fromList [proposer, counterparty]
|
||||||
|
contextId = None
|
||||||
|
steps = [recStep, payStep]
|
||||||
|
|
||||||
|
-- INSTRUCT_BEGIN
|
||||||
|
(containerCid, [recInstructionCid, payInstructionCid]) <-
|
||||||
|
exercise settlementFactoryCid Settlement.Instruct with
|
||||||
|
instructors = fromList [proposer, counterparty]
|
||||||
|
settlers = singleton proposer
|
||||||
|
id = Id id
|
||||||
|
description = "Settlement for " <> id
|
||||||
|
contextId = None
|
||||||
|
routedSteps
|
||||||
|
settlementTime = None -- i.e., immediate settlement
|
||||||
|
-- INSTRUCT_END
|
||||||
|
|
||||||
|
pure (containerCid, recInstructionCid, payInstructionCid)
|
||||||
|
|
||||||
|
choice Decline : ()
|
||||||
|
-- ^ Decline the request.
|
||||||
|
controller counterparty
|
||||||
|
do pure ()
|
||||||
|
|
||||||
|
choice Withdraw : ()
|
||||||
|
-- ^ Withdraw the request.
|
||||||
|
controller proposer
|
||||||
|
do pure ()
|
6
daml/Workflow/README.md
Normal file
6
daml/Workflow/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Workflows
|
||||||
|
|
||||||
|
This folder includes user-defined workflows which encapsulate the core business logic of the
|
||||||
|
application.
|
||||||
|
|
||||||
|
Files in this folder can reference only the interface packages of `daml-finance`.
|
55
daml/Workflow/Transfer.daml
Normal file
55
daml/Workflow/Transfer.daml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
module Workflow.Transfer where
|
||||||
|
|
||||||
|
import DA.Assert ((===))
|
||||||
|
import DA.Set (fromList)
|
||||||
|
import Daml.Finance.Interface.Holding.Base qualified as Holding (I)
|
||||||
|
import Daml.Finance.Interface.Holding.Transferable qualified as Transferable (I, Transfer(..))
|
||||||
|
import Daml.Finance.Interface.Holding.Util (getAmount, getInstrument)
|
||||||
|
import Daml.Finance.Interface.Types.Common.Types (AccountKey(..), InstrumentKey)
|
||||||
|
|
||||||
|
-- | Initiate / Accept template to transfer a holding to a new owner.
|
||||||
|
template Request
|
||||||
|
with
|
||||||
|
receiverAccount : AccountKey
|
||||||
|
-- ^ The account where the holding is sent.
|
||||||
|
instrument : InstrumentKey
|
||||||
|
-- ^ The instrument referenced by the holding to be transferred.
|
||||||
|
amount : Decimal
|
||||||
|
-- ^ Number of units to be transferred.
|
||||||
|
currentOwner : Party
|
||||||
|
-- ^ The owner of the holding to be transferred.
|
||||||
|
where
|
||||||
|
signatory receiverAccount.owner
|
||||||
|
observer currentOwner
|
||||||
|
|
||||||
|
ensure amount > 0.0
|
||||||
|
|
||||||
|
choice Accept : ContractId Holding.I
|
||||||
|
with
|
||||||
|
holdingCid : ContractId Holding.I
|
||||||
|
controller currentOwner
|
||||||
|
do
|
||||||
|
-- Sanity checks
|
||||||
|
holding <- fetch holdingCid
|
||||||
|
getAmount holding === amount
|
||||||
|
getInstrument holding === instrument
|
||||||
|
|
||||||
|
-- DO_TRANSFER_BEGIN
|
||||||
|
let transferableCid = coerceInterfaceContractId @Transferable.I holdingCid
|
||||||
|
|
||||||
|
newTransferableCid <- exercise transferableCid Transferable.Transfer with
|
||||||
|
actors = fromList [currentOwner, receiverAccount.owner]
|
||||||
|
newOwnerAccount = receiverAccount
|
||||||
|
|
||||||
|
pure $ toInterfaceContractId @Holding.I newTransferableCid
|
||||||
|
-- DO_TRANSFER_END
|
||||||
|
|
||||||
|
choice Decline : ()
|
||||||
|
-- ^ Decline the request.
|
||||||
|
controller currentOwner
|
||||||
|
do pure ()
|
||||||
|
|
||||||
|
choice Withdraw : ()
|
||||||
|
-- ^ Withdraw the request.
|
||||||
|
controller receiverAccount.owner
|
||||||
|
do pure ()
|
21
get-dependencies.bat
Normal file
21
get-dependencies.bat
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
:: Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||||
|
:: SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
:: Create .lib directory
|
||||||
|
if exist ".\.lib\" rmdir /s /q .lib
|
||||||
|
mkdir .\.lib
|
||||||
|
|
||||||
|
:: Get the dependency list
|
||||||
|
echo Downloading the list of dependencies
|
||||||
|
for /f "tokens=2" %%a IN ('findstr "^version" daml.yaml') DO (set version=%%a)
|
||||||
|
|
||||||
|
curl -Lf# "https://raw.githubusercontent.com/digital-asset/daml-finance/main/docs/code-samples/getting-started-config/%version%.conf" -o .lib/%version%.conf
|
||||||
|
|
||||||
|
for /F "tokens=*" %%a in (.lib/%version%.conf) do (
|
||||||
|
for /F "tokens=1,2" %%b in ("%%a") do (
|
||||||
|
echo Downloading: %%b to %%c
|
||||||
|
curl -Lf# "%%b" -o %%c
|
||||||
|
)
|
||||||
|
)
|
28
get-dependencies.sh
Executable file
28
get-dependencies.sh
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Create .lib directory
|
||||||
|
if [[ -d .lib ]]; then
|
||||||
|
rm -r .lib
|
||||||
|
fi
|
||||||
|
mkdir .lib
|
||||||
|
|
||||||
|
# Get the dependency list
|
||||||
|
echo "Downloading the list of dependencies"
|
||||||
|
version=$(grep '^version' daml.yaml | cut -d " " -f 2)
|
||||||
|
curl -L# \
|
||||||
|
-H 'Cache-Control: no-cache, no-store' \
|
||||||
|
-o .lib/${version}.conf \
|
||||||
|
https://raw.githubusercontent.com/digital-asset/daml-finance/main/docs/code-samples/getting-started-config/${version}.conf
|
||||||
|
|
||||||
|
# For each dependency, download and install
|
||||||
|
while IFS=" " read -r url out
|
||||||
|
do
|
||||||
|
printf "Downloading: %s, to: %s\n" "$url" "$out"
|
||||||
|
curl -Lf# "${url}" -o ${out}
|
||||||
|
done < .lib/${version}.conf
|
||||||
|
|
||||||
|
echo "All dependencies successfully downloaded!"
|
Loading…
Reference in New Issue
Block a user