From ab6a85a0a02286e03d6b5dd28a30347984058926 Mon Sep 17 00:00:00 2001 From: markus-da <103116047+markus-da@users.noreply.github.com> Date: Tue, 23 May 2023 14:59:56 +0200 Subject: [PATCH] update daml finance quickstarter (#16899) --- .../daml/Scripts/Holding.daml | 173 ++++++++++++++++++ .../daml/Scripts/Lifecycling.daml | 2 +- .../daml/Scripts/Settlement.daml | 6 +- .../daml/Scripts/Transfer.daml | 116 ++---------- .../daml/Workflow/CreateAccount.daml | 9 +- .../quickstart-finance/daml/Workflow/DvP.daml | 2 +- .../daml/Workflow/Transfer.daml | 2 +- 7 files changed, 200 insertions(+), 110 deletions(-) create mode 100644 templates/quickstart-finance/daml/Scripts/Holding.daml diff --git a/templates/quickstart-finance/daml/Scripts/Holding.daml b/templates/quickstart-finance/daml/Scripts/Holding.daml new file mode 100644 index 00000000000..96f0fbe5305 --- /dev/null +++ b/templates/quickstart-finance/daml/Scripts/Holding.daml @@ -0,0 +1,173 @@ +module Scripts.Holding 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(..), Fungible(..)) +import Daml.Finance.Instrument.Token.Instrument (Instrument(..)) + +import Workflow.CreateAccount qualified as CreateAccount +import Workflow.CreditAccount qualified as CreditAccount + +-- | Helper container used to transfer state from one script to another. +data HoldingState = HoldingState + with + alice : Party + bank : Party + bob : Party + public : Party + aliceAccount : AccountKey + bobAccount : AccountKey + cashInstrument : InstrumentKey + holdingFactoryCid : ContractId Holding.F + aliceCashHoldingCid : 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 +runHolding : Script HoldingState +runHolding = 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" + instrumentKey = InstrumentKey with + issuer = bank + depository = bank + id = instrumentId + version = instrumentVersion + 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 and Bank create a holding directly using the template + -- CREATE_ALICE_DIRECT_HOLDING_BEGIN + aliceHoldingRequest <- submit alice do + createCmd HoldingRequest with + instrument = instrumentKey + account = aliceAccount + amount = 1000.0 + owner = alice + custodian = bank + + aliceHoldingCid <- submit bank do exerciseCmd aliceHoldingRequest Accept + -- CREATE_ALICE_DIRECT_HOLDING_END + + -- Alice deposits cash at the bank + -- CREATE_ALICE_HOLDING_BEGIN + aliceRequestCid <- submit alice do + createCmd CreditAccount.Request with + account = aliceAccount + instrument = instrumentKey + amount = 1000.0 + + aliceCashHoldingCid <- submit bank do exerciseCmd aliceRequestCid CreditAccount.Accept + -- CREATE_ALICE_HOLDING_END + + pure HoldingState with + alice + bank + bob + public + aliceAccount + bobAccount + cashInstrument = instrumentKey + holdingFactoryCid + aliceCashHoldingCid + +-- | 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 + +-- | Propose / Accept template to create a holding. +template HoldingRequest + with + owner : Party + -- ^ Owner of the holding. + custodian : Party + -- ^ Custodian of the holding. + instrument : InstrumentKey + -- ^ The instrument of which units are held. + account : AccountKey + -- ^ The account at which the holding is held. Defines the holding's owner and custodian. + amount : Decimal + -- ^ Number of units. + where + signatory owner + observer custodian + + choice Accept : ContractId Fungible.Fungible + controller custodian + do + create Fungible.Fungible with + instrument + account + amount + lock = None + observers = empty diff --git a/templates/quickstart-finance/daml/Scripts/Lifecycling.daml b/templates/quickstart-finance/daml/Scripts/Lifecycling.daml index 5181236f5fa..547081468ba 100644 --- a/templates/quickstart-finance/daml/Scripts/Lifecycling.daml +++ b/templates/quickstart-finance/daml/Scripts/Lifecycling.daml @@ -112,7 +112,7 @@ runLifecycling = do exerciseCmd lifecycleClaimRuleCid Claim.ClaimEffect with claimer = bob holdingCids = [bobHoldingCid] - effectCid + effectCid -- This is equivalent to writing effectCid = effectCid batchId = Id "DistributionSettlement" let [bobInstructionCid, bankInstructionCid, couponInstructionCid] = result.instructionCids -- CLAIM_EVENT_END diff --git a/templates/quickstart-finance/daml/Scripts/Settlement.daml b/templates/quickstart-finance/daml/Scripts/Settlement.daml index ef311c4bd97..946f70d3d86 100644 --- a/templates/quickstart-finance/daml/Scripts/Settlement.daml +++ b/templates/quickstart-finance/daml/Scripts/Settlement.daml @@ -96,7 +96,7 @@ runSettlement = do -- ROUTE_PROVIDER_BEGIN routeProviderCid <- toInterfaceContractId @RouteProvider.I <$> submit bank do createCmd SingleCustodian with - provider = bank; observers = S.fromList [alice, bob] ; custodian = bank + provider = bank; observers = S.fromList [alice, bob]; custodian = bank -- ROUTE_PROVIDER_END -- Setup a Settlement Factory facility @@ -117,7 +117,7 @@ runSettlement = do payQuantity = qty 1000.0 usdInstrument proposer = bob counterparty = alice - routeProviderCid + routeProviderCid -- This is equivalent to writing routeProviderCid = routeProviderCid settlementFactoryCid -- DVP_PROPOSE_END @@ -159,7 +159,7 @@ runSettlement = do actors = singleton bob -- SETTLE_END - pure $ SettlementState with + pure SettlementState with alice bank bob diff --git a/templates/quickstart-finance/daml/Scripts/Transfer.daml b/templates/quickstart-finance/daml/Scripts/Transfer.daml index 4a2f9e421ea..4652107912d 100644 --- a/templates/quickstart-finance/daml/Scripts/Transfer.daml +++ b/templates/quickstart-finance/daml/Scripts/Transfer.daml @@ -1,25 +1,17 @@ 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(..)) +import Daml.Finance.Interface.Types.Common.Types (AccountKey, 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 +import Scripts.Holding (HoldingState(..), runHolding) + -- | Helper container used to transfer state from one script to another. data TransferState = TransferState with @@ -34,95 +26,25 @@ data TransferState = TransferState 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 +-- | Test script that transfers a holding from Alice to Bob runTransfer : Script TransferState runTransfer = do - -- Allocate parties - [alice, bank, bob, public] <- mapA createParty $ ["Alice", "Bank", "Bob", "Public"] + -- Execute the `runHolding` script. Alice now holds USD 1000 in her account. + HoldingState{alice + , bank + , bob + , public + , aliceAccount + , bobAccount + , cashInstrument + , holdingFactoryCid + , aliceCashHoldingCid} <- runHolding - -- 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 @@ -134,7 +56,7 @@ runTransfer = do exerciseCmd transferRequestCid Transfer.Accept with holdingCid = aliceCashHoldingCid -- TRANSFER_END - pure $ TransferState with + pure TransferState with alice bank bob @@ -144,11 +66,3 @@ runTransfer = do 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 diff --git a/templates/quickstart-finance/daml/Workflow/CreateAccount.daml b/templates/quickstart-finance/daml/Workflow/CreateAccount.daml index 956eeb959d3..850115bf94e 100644 --- a/templates/quickstart-finance/daml/Workflow/CreateAccount.daml +++ b/templates/quickstart-finance/daml/Workflow/CreateAccount.daml @@ -38,13 +38,16 @@ template Request controller custodian do let + accountKey = AccountKey with + custodian -- This is equivalent to writing custodian = custodian + owner + id = Id label 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 + description + holdingFactoryCid controllers = Account.Controllers with outgoing = S.singleton owner incoming = S.singleton owner diff --git a/templates/quickstart-finance/daml/Workflow/DvP.daml b/templates/quickstart-finance/daml/Workflow/DvP.daml index 418fbfa2bb3..0a0d1ddd65b 100644 --- a/templates/quickstart-finance/daml/Workflow/DvP.daml +++ b/templates/quickstart-finance/daml/Workflow/DvP.daml @@ -4,7 +4,7 @@ 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.RouteProvider qualified as RouteProvider (Discover(..), I) import Daml.Finance.Interface.Settlement.Types (Step(..)) import Daml.Finance.Interface.Types.Common.Types (Id(..), InstrumentQuantity) diff --git a/templates/quickstart-finance/daml/Workflow/Transfer.daml b/templates/quickstart-finance/daml/Workflow/Transfer.daml index 5ea4f768652..8238c30aed0 100644 --- a/templates/quickstart-finance/daml/Workflow/Transfer.daml +++ b/templates/quickstart-finance/daml/Workflow/Transfer.daml @@ -3,7 +3,7 @@ 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.Transferable qualified as Transferable (Transfer(..), I) import Daml.Finance.Interface.Holding.Util (getAmount, getInstrument) import Daml.Finance.Interface.Types.Common.Types (AccountKey(..), InstrumentKey)