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