update daml finance quickstarter (#16899)

This commit is contained in:
markus-da 2023-05-23 14:59:56 +02:00 committed by GitHub
parent 943e140bbb
commit ab6a85a0a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 200 additions and 110 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)

View File

@ -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)