/
age001-proposal-voting.clar
167 lines (139 loc) · 6.21 KB
/
age001-proposal-voting.clar
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
;; Title: age001 Proposal Voting
;; Author: Marvin Janssen
;; Depends-On: EDE000
;; Synopsis:
;; This extension is part of the core of ExecutorDAO. It allows governance token
;; holders to vote on and conclude proposals.
;; Description:
;; Once proposals are submitted, they are open for voting after a lead up time
;; passes. Any token holder may vote on an open proposal, where one token equals
;; one vote. Members can vote until the voting period is over. After this period
;; anyone may trigger a conclusion. The proposal will then be executed if the
;; votes in favour exceed the ones against.
(impl-trait .extension-trait.extension-trait)
(use-trait proposal-trait .proposal-trait.proposal-trait)
(use-trait governance-token-trait .governance-token-trait.governance-token-trait)
(define-constant err-unauthorised (err u3000))
(define-constant err-not-governance-token (err u3001))
(define-constant err-proposal-already-executed (err u3002))
(define-constant err-proposal-already-exists (err u3003))
(define-constant err-unknown-proposal (err u3004))
(define-constant err-proposal-already-concluded (err u3005))
(define-constant err-proposal-inactive (err u3006))
(define-constant err-proposal-not-concluded (err u3007))
(define-constant err-no-votes-to-return (err u3008))
(define-constant err-end-block-height-not-reached (err u3009))
(define-constant err-disabled (err u3010))
(define-constant err-transfer-failed (err u3011))
(define-data-var governance-token-principal principal .age000-governance-token)
(define-map proposals
principal
{
votes-for: uint,
votes-against: uint,
start-block-height: uint,
end-block-height: uint,
concluded: bool,
passed: bool,
proposer: principal
}
)
(define-map member-total-votes {proposal: principal, voter: principal, governance-token: principal} uint)
;; --- Authorisation check
(define-public (is-dao-or-extension)
(ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) err-unauthorised))
)
;; --- Internal DAO functions
;; Governance token
(define-public (set-governance-token (governance-token <governance-token-trait>))
(begin
(try! (is-dao-or-extension))
(ok (var-set governance-token-principal (contract-of governance-token)))
)
)
;; Proposals
(define-public (add-proposal (proposal <proposal-trait>) (data {start-block-height: uint, end-block-height: uint, proposer: principal}))
(begin
(try! (is-dao-or-extension))
(asserts! (is-none (contract-call? .executor-dao executed-at proposal)) err-proposal-already-executed)
(print {event: "propose", proposal: proposal, proposer: tx-sender})
(ok (asserts! (map-insert proposals (contract-of proposal) (merge {votes-for: u0, votes-against: u0, concluded: false, passed: false} data)) err-proposal-already-exists))
)
)
;; --- Public functions
;; Governance token
(define-read-only (get-governance-token)
(var-get governance-token-principal)
)
(define-private (is-governance-token (governance-token <governance-token-trait>))
(ok (asserts! (is-eq (contract-of governance-token) (var-get governance-token-principal)) err-not-governance-token))
)
;; Proposals
(define-read-only (get-proposal-data (proposal principal))
(map-get? proposals proposal)
)
;; Votes
(define-read-only (get-current-total-votes (proposal principal) (voter principal) (governance-token principal))
(default-to u0 (map-get? member-total-votes {proposal: proposal, voter: voter, governance-token: governance-token}))
)
(define-public (vote (amount uint) (for bool) (proposal principal) (governance-token <governance-token-trait>))
(let
(
(proposal-data (unwrap! (map-get? proposals proposal) err-unknown-proposal))
(token-principal (contract-of governance-token))
)
(try! (is-governance-token governance-token))
(asserts! (>= block-height (get start-block-height proposal-data)) err-proposal-inactive)
(asserts! (< block-height (get end-block-height proposal-data)) err-proposal-inactive)
(map-set member-total-votes {proposal: proposal, voter: tx-sender, governance-token: token-principal}
(+ (get-current-total-votes proposal tx-sender token-principal) amount)
)
(map-set proposals proposal
(if for
(merge proposal-data {votes-for: (+ (get votes-for proposal-data) amount)})
(merge proposal-data {votes-against: (+ (get votes-against proposal-data) amount)})
)
)
(print {event: "vote", proposal: proposal, voter: tx-sender, for: for, amount: amount})
(contract-call? governance-token edg-lock amount tx-sender)
)
)
;; Conclusion
(define-public (conclude (proposal <proposal-trait>))
(let
(
(proposal-data (unwrap! (map-get? proposals (contract-of proposal)) err-unknown-proposal))
(passed (> (get votes-for proposal-data) (get votes-against proposal-data)))
)
(asserts! (not (get concluded proposal-data)) err-proposal-already-concluded)
(asserts! (>= block-height (get end-block-height proposal-data)) err-end-block-height-not-reached)
(map-set proposals (contract-of proposal) (merge proposal-data {concluded: true, passed: passed}))
(print {event: "conclude", proposal: proposal, passed: passed})
(and passed (try! (contract-call? .executor-dao execute proposal tx-sender)))
(ok passed)
)
)
;; Reclamation
(define-public (reclaim-votes (proposal <proposal-trait>) (governance-token <governance-token-trait>))
(let
(
(proposal-principal (contract-of proposal))
(token-principal (contract-of governance-token))
(proposal-data (unwrap! (map-get? proposals proposal-principal) err-unknown-proposal))
(votes (unwrap! (map-get? member-total-votes {proposal: proposal-principal, voter: tx-sender, governance-token: token-principal}) err-no-votes-to-return))
)
(asserts! (get concluded proposal-data) err-proposal-not-concluded)
(map-delete member-total-votes {proposal: proposal-principal, voter: tx-sender, governance-token: token-principal})
(contract-call? governance-token edg-unlock votes tx-sender)
)
)
(define-public (reclaim-and-vote (amount uint) (for bool) (proposal principal) (reclaim-from <proposal-trait>) (governance-token <governance-token-trait>))
(begin
(try! (reclaim-votes reclaim-from governance-token))
(vote amount for proposal governance-token)
)
)
;; --- Extension callback
(define-public (callback (sender principal) (memo (buff 34)))
(ok true)
)