Multiple party agreement模式使用pending合約作爲協議合約(agreement contract)的包裝。 簽署方中的任何一方都可以通過在分類帳上創建pending合約來啓動工作流程,並將自己填入在signatory字段中。 除非所有各方都同意pending合約,並用自己的簽名替換髮起人的簽名,否則不會在分類帳上創建協議合同。
動機
Initiate and Accept模式展示瞭如何在DAML中創建雙邊協議。 但是,一個項目或工作流通常需要兩個以上的參與者才能達成共識,並將他們的簽名放到多方合約中。 例如,在一個大型建築項目中,至少有三個主要利益相關者:所有者,建築師和建造者。 在開始施工之前,所有三個方面都需要就主要職責和項目成功標準達成協議。
如果將這樣的協議建模爲三個單獨的雙邊協議,則任何一方都無法確定其兩個合約與合作伙伴之間的第三份合約是否存在衝突。 如果使用Initiate and Accept模式來收集多方協議上的三個簽名,則將對共識順序施加不必要的限制,並且將需要一些其他合約模板(contract templates)作爲中間步驟。 兩種解決方案都不理想。
遵循多方協議模式,很容易與多個簽署方簽訂協議合同,並讓各方明確接受
實現
Agreement contract
Agreement contract代表了一組利益相關者之間的最終協議。 它的內容可以隨業務案例而變化,但是在這種模式下,它始終具有多個簽名者。
template Agreement
with
signatories: [Party]
where
signatory signatories
ensure
unique signatories
-- The rest of the template to be agreed to would follow here
Pending contract
Pending contract需要包含擬議的協議合同的內容作爲參數。 這樣一來,各方可以知道他們要同意的是什麼,在所有各方簽署後Agreement contract就能被創建了。
Pending contract包含已簽約的當事人列表和尚未簽約的當事人列表。 如果將這些列表加在一起,則它必須與Agreement contract的簽署者列表一致。
所有toSign
參與者都可以選擇簽名。 此choice將檢查該方是否確實是toSign
的成員,然後創建這個Pending contract的新實例,在該實例中它們已被移至signed
列表。
template Pending
with
finalContract: Agreement
alreadySigned: [Party]
where
signatory alreadySigned
observer finalContract.signatories
ensure
-- Can't have duplicate signatories
unique alreadySigned
-- The parties who need to sign is the finalContract.signatories with alreadySigned filtered out
let toSign = filter (`notElem` alreadySigned) finalContract.signatories
choice Sign : ContractId Pending with
signer : Party
controller signer
do
-- Check the controller is in the toSign list, and if they are, sign the Pending contract
assert (signer `elem` toSign)
create this with alreadySigned = signer :: alreadySigned
一旦所有當事方都簽署了,任何一方都可以使用Finalize
choice 來創建最終的Agreement contract。 這將檢查該協議的所有簽署方是否已簽署Pending contract。
Collecting the signatures in practice
由於最終的待定合同具有多個簽署者,因此任何一個涉衆都不能在該狀態下創建該合同。
parties@[person1, person2, person3, person4] <- makePartiesFrom ["Alice", "Bob", "Clare", "Dave"]
let finalContract = Agreement with signatories = parties
-- Parties cannot create a contract already signed by someone else
initialFailTest <- person1 `submitMustFail` do
create Pending with finalContract; alreadySigned = [person1, person2]
-- Any party can create a Pending contract provided they list themselves as the only signatory
pending <- person1 `submit` do
create Pending with finalContract; alreadySigned = [person1]
一旦創建了Pending contract,其他各方就可以簽署該合同。 爲簡單起見,示例代碼僅具有表達共識的choices(但您可能希望添加到“接受”,“拒絕”或“協商”)。
-- Each signatory of the finalContract can Sign the Pending contract
pending <- person2 `submit` do
exercise pending Sign with signer = person2
pending <- person3 `submit` do
exercise pending Sign with signer = person3
pending <- person4 `submit` do
exercise pending Sign with signer = person4
-- A party can't sign the Pending contract twice
pendingFailTest <- person3 `submitMustFail` do
exercise pending Sign with signer = person3
-- A party can't sign on behalf of someone else
pendingFailTest <- person3 `submitMustFail` do
exercise pending Sign with signer = person4
一旦所有當事方都簽署了Pending contract,任何一方都可以執行Finalize
choice。 這將在賬本上創建Agreement contract。
person1 `submit` do
exercise pending Finalize with signer = person1