Initial commit

This commit is contained in:
Rune K. Svendsen 2023-05-08 16:09:16 -04:00
commit 1e6d4aa792
13 changed files with 840 additions and 0 deletions

10
README.md Normal file
View 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
View 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

View 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
View 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`.

View 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
View 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

View 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 ()

View 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
View 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
View 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`.

View 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
View 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
View 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!"