escrow_actions.gno
3.79 Kb · 113 lines
1package memba_weighted_host
2
3import (
4 "chain"
5 "gno.land/p/samcrew/memba_weighted_policy"
6 "strconv"
7)
8
9const EscrowPath = "gno.land/r/samcrew/escrow_v4"
10
11type EscrowActionKind string
12
13const (
14 EscrowAcceptOwner EscrowActionKind = "accept-owner"
15 EscrowReturnOwner EscrowActionKind = "return-owner"
16 EscrowAbortReturn EscrowActionKind = "abort-return"
17 EscrowUnpause EscrowActionKind = "unpause"
18 EscrowRefundClient EscrowActionKind = "refund-client"
19 EscrowPayFreelancer EscrowActionKind = "pay-freelancer"
20 // EscrowSetFeeRecipient stages a new fallback fee recipient (escrow_v4
21 // two-step rotation); the staged address accepts with its own transaction.
22 EscrowSetFeeRecipient EscrowActionKind = "set-fee-recipient"
23)
24
25type EscrowPolicy struct{ dao, successor address }
26
27func NewEscrowPolicy(dao, successor address) EscrowPolicy {
28 if !dao.IsValid() || dao != chain.PackageAddress("gno.land/r/samcrew/memba_dao") {
29 panic("escrow policy requires the founding DAO address")
30 }
31 if !successor.IsValid() || successor == dao || successor == chain.PackageAddress(EscrowPath) {
32 panic("escrow policy requires a valid distinct successor")
33 }
34 return EscrowPolicy{dao: dao, successor: successor}
35}
36func (p EscrowPolicy) DAO() address { return p.dao }
37func (p EscrowPolicy) Successor() address { return p.successor }
38
39type EscrowAction struct {
40 kind EscrowActionKind
41 recipient address
42 contractID string
43 milestone int
44}
45
46func (p EscrowPolicy) Accept() EscrowAction { return EscrowAction{kind: EscrowAcceptOwner} }
47func (p EscrowPolicy) Return() EscrowAction {
48 return EscrowAction{kind: EscrowReturnOwner, recipient: p.successor}
49}
50func (p EscrowPolicy) AbortReturn() EscrowAction {
51 return EscrowAction{kind: EscrowAbortReturn, recipient: p.successor}
52}
53func EscrowResume() EscrowAction { return EscrowAction{kind: EscrowUnpause} }
54func EscrowFeeRecipient(recipient address) EscrowAction {
55 a := EscrowAction{kind: EscrowSetFeeRecipient, recipient: recipient}
56 a.Bytes()
57 return a
58}
59func EscrowResolution(id string, index int, refund bool) EscrowAction {
60 kind := EscrowPayFreelancer
61 if refund {
62 kind = EscrowRefundClient
63 }
64 a := EscrowAction{kind: kind, contractID: id, milestone: index}
65 a.Bytes()
66 return a
67}
68func (a EscrowAction) Kind() EscrowActionKind { return a.kind }
69func (a EscrowAction) Recipient() address { return a.recipient }
70func (a EscrowAction) ContractID() string { return a.contractID }
71func (a EscrowAction) Milestone() int { return a.milestone }
72func (a EscrowAction) IsResolution() bool {
73 return a.kind == EscrowRefundClient || a.kind == EscrowPayFreelancer
74}
75func (a EscrowAction) Bytes() string {
76 base := "escrow/v1|" + EscrowPath + "|" + string(a.kind)
77 if a.IsResolution() {
78 n, err := strconv.ParseUint(a.contractID, 10, 64)
79 if err != nil || strconv.FormatUint(n, 10) != a.contractID || a.milestone < 0 || a.milestone >= 20 || a.recipient != "" {
80 panic("invalid escrow resolution action")
81 }
82 return base + "|" + a.contractID + "|" + strconv.Itoa(a.milestone)
83 }
84 if a.contractID != "" || a.milestone != 0 {
85 panic("malformed escrow action")
86 }
87 switch a.kind {
88 case EscrowAcceptOwner, EscrowUnpause:
89 if a.recipient != "" {
90 panic("malformed escrow action")
91 }
92 return base
93 case EscrowReturnOwner, EscrowAbortReturn:
94 if !a.recipient.IsValid() {
95 panic("invalid escrow return action")
96 }
97 return base + "|" + string(a.recipient)
98 case EscrowSetFeeRecipient:
99 if !a.recipient.IsValid() {
100 panic("invalid escrow fee recipient action")
101 }
102 return base + "|" + string(a.recipient)
103 default:
104 panic("unsupported escrow action")
105 }
106}
107func (a EscrowAction) Category() memba_weighted_policy.Category {
108 a.Bytes()
109 if a.IsResolution() || a.kind == EscrowUnpause || a.kind == EscrowSetFeeRecipient {
110 return memba_weighted_policy.Financial
111 }
112 return memba_weighted_policy.Critical
113}