Consider the following model, where I can have multiple outstanding offers for an asset to be transferred.
template ProposeAsset
with
assetId : ContractId Asset
owner : Party
recipient : Party
where
signatory owner
observer recipient
choice Accept : ContractId AcceptAsset
controller recipient
do create AcceptAsset with assetId, currentOwner = owner, newOwner = recipient
template AcceptAsset
with
assetId : ContractId Asset
currentOwner : Party
newOwner : Party
where
signatory newOwner
observer currentOwner
choice Finalize : ContractId Asset
controller currentOwner
do
archive assetId
create Asset with owner = newOwner
template Asset
with
owner : Party
where
signatory owner
nonconsuming choice Propose : ContractId ProposeAsset
with
recipient : Party
controller owner
do create ProposeAsset with
assetId = self
owner = owner
recipient = recipient
This model is prone to contention, as shown in the following test script, which “successfully fails”:
testAssetCannotBeGivenTwice : Script ()
testAssetCannotBeGivenTwice = script do
-- user_setup_begin
alice <- allocatePartyWithHint "Alice" (PartyIdHint "Alice")
bob <- allocatePartyWithHint "Bob" (PartyIdHint "Bob")
charlie <- allocatePartyWithHint "Charlie" (PartyIdHint "Charlie")
aliceId <- validateUserId "alice"
bobId <- validateUserId "bob"
charlieId <- validateUserId "charlie"
createUser (User aliceId (Some alice)) [CanActAs alice]
createUser (User bobId (Some bob)) [CanActAs bob]
createUser (User charlieId (Some charlie)) [CanActAs charlie]
-- user_setup_end
asset <- submit alice do
createCmd Asset with
owner = alice
offerToBob <- submit alice do
exerciseCmd asset Propose with recipient = bob
bobAccepts <- submit bob do exerciseCmd offerToBob Accept
offerToCharlie <- submit alice do
exerciseCmd asset Propose with recipient = charlie
charlieAccepts <- submit charlie do exerciseCmd offerToCharlie Accept
submit alice do exerciseCmd bobAccepts Finalize
submitMustFail alice do exerciseCmd charlieAccepts Finalize
Ideally, I would like to handle contention-related issues explicitly in my model.
For this reason, I would like to catch CONTRACT_NOT_FOUND
errors and return an Optional ContractId Asset
. Is that possible?