-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmulti-sig-manager.pact
99 lines (76 loc) · 3.37 KB
/
multi-sig-manager.pact
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
(module multi-sig-manager GOVERNANCE
(use util.guards1)
(defcap GOVERNANCE ()
; Should be not upgradable but for tests it's OK
(enforce-keyset "user.multi-sig-admin"))
(defschema domain-sch
domain:string
signers:[guard]
required-signers:integer
)
(defschema transaction-sch
trx-hash:string
domain:string
approvals-count:integer
)
(defschema approval-sch
approved:bool
)
(deftable domains:{domain-sch})
(deftable transactions:{transaction-sch})
(deftable approvals:{approval-sch})
(defun enforce-valid-signers:bool (signers:[guard] required-signers:integer)
; Check required signers
(enforce (and? (< 0) (>= (length signers)) required-signers) "Required signers count is bad")
; Check for duplicates
(enforce (= (length signers) (length (distinct signers))) "Duplicates in guards")
)
(defun add-domain:string (domain:string signers:[guard] required-signers:integer)
@doc "Create a new signature domain"
(enforce-valid-signers signers required-signers)
(insert domains domain {'domain:domain,
'signers:signers,
'required-signers:required-signers})
)
(defun rotate-domain:string (domain:string signers:[guard] required-signers:integer)
@doc "Rotate an existing domain"
(enforce-approved domain)
(enforce-valid-signers signers required-signers)
(update domains domain {'signers:signers,
'required-signers:required-signers})
)
(defun propose-transaction:string (domain:string trx-hash:string)
@doc "First step => Someone propose a transaction"
; Verify that the proposer is a signer of the domain
(with-read domains domain {'signers:=domain-signers}
(enforce-guard-any domain-signers))
(insert transactions trx-hash {'trx-hash:trx-hash,
'domain:domain,
'approvals-count:0})
)
(defun approve:string (trx-hash:string approver-guard:guard)
@doc "Second step => Approvers approve"
; First enforce the guard
(enforce-guard approver-guard)
; Ensure that this approval is not a duplicate
(insert approvals (hash (+ trx-hash (hash approver-guard))) {'approved:true})
(with-read transactions trx-hash {'domain:=domain, 'approvals-count:=old-approvals-count}
; Check that the signer is allowed for this domain
(with-read domains domain {'signers:=signers}
(enforce (contains approver-guard signers) "Guard is not allowed to sign this transaction"))
; Update the approvals-count
(update transactions trx-hash {'approvals-count: (+ 1 old-approvals-count)}))
)
(defun enforce-approved:bool (domain:string)
@doc "Third step => Include this call in module GOVERNANCE"
(with-read domains domain {'required-signers:=required-signers}
(with-default-read transactions (tx-hash) {'domain:"", 'approvals-count:0}
{'approvals-count:=approvals-count, 'domain:=tx-domain}
(enforce (!= tx-domain "") "Transaction not registered")
(enforce (= domain tx-domain) "Bad domain name")
(enforce (>= approvals-count required-signers) "Not enough approvals")))
)
(defun get-approved-guard:guard (domain:string)
@doc "Guard can be used for account or namespace"
(create-user-guard (enforce-approved domain)))
)